1. 程式人生 > >Python字符編碼與函數基本使用-day3

Python字符編碼與函數基本使用-day3

you rgs 內置函數 無法 lov 格式 img 這一 day3

  • 解決Python2和Python3中字符編碼的問題
  • 補充Python2中文件操作的說明
  • 函數使用基礎
  • 函數的類型

一、Python2中的字符存在的解碼編碼問題

  如果是現在正在用Python2的人應該都知道存在字符編碼問題,就舉一個最簡單的例子吧:Python2是無法在命令行直接打印中文的,當然他也是不會報錯的,頂多是一堆你看不懂的亂碼。如果想在直接顯示中文,我們是可以在Python2文件頭部申明字符編碼的格式。如下圖

技術分享

這裏 #-*-coding:utf-8 -*- 是用來申明下面的代碼是用什麽編碼來解釋;

 1.1.Python2中的解碼和編碼:

  在編碼和解碼的世界中,我們得需要找一個大家都知道的文字。也可以這麽理解。我是一個中國人現在和一個日本人溝通,我肯定是無法理解他說的是什麽,他同樣也無法理解,但是這樣就沒有辦法了嗎?或許我們需要一個國際的語言——英語。這樣來自不同國家的人也可以進行溝通了(雖然我知道 are you ok 0-0)。在編碼中也是一樣,gbk和utf-8都不知道對方的格式是什麽吊意思。所以如果要上gbk讀懂utf-8的編碼就得將utf-8 decode成 Unicode,而Unicode有知道gkb,這裏需要將Unicode在encode成gbk就行了

技術分享

#-*- coding:utf-8 -*-


msg = "中國"
print msg

#解碼在編碼的過程,encoding是申明用申明這段代碼是什麽編碼
gbk_str = msg.decode(encoding=utf-8).encode(encoding=gbk)
print gbk_str

#其實兩種輸出的結果是一樣的

在Python2中默認是使用gbk來解釋IDE中的代碼的,所以無法直接在Python命令行中直接輸入中文,所以我們才會使用 #-*-coding:utf-8 -*-來申明頭部,我們到底需要使用什麽語言來解釋下面代碼。細心的人肯定是發現了一個問題,申明頭部只是使用utf-8來解釋下面的話,按理說命令行中雖然不報錯,但是應該也是亂碼才是,這裏為啥會直接輸出中文呢畢竟DOS命令行中默認支持的是gbk格式的字符代碼呀?這裏就涉及到另外的一個概念了。Python到內存解釋器裏面,默認是用的Unicode,文件加載到內存後自動解碼成Unicode,而Unicode是外國碼,自然也就可以翻譯來自utf-8的編碼,也可以翻譯成gbk的編碼了。顧可以顯示中文了。

PS:這裏我們得出一個結論:python2 中解碼動作是必須的,但是編碼可以不用,因為內存就是Unicode

1.2、Python3中字符編碼的問題:

  額,這還有什麽可以說的呢?Python3默認就是使用utf-8解釋代碼的。也就是行首自帶 #-*-coding:utf-8 -*-(GBM),所以也就不存在解碼的問題。但是我在這裏提上一嘴(其實就是怕自己以後也忘了,嘿嘿),如果我們將utf-8的字符編碼的格式給編碼成gbk。這裏會輸出bytes格式的東西。

技術分享

  bytes到底是什麽東西呢?這裏我簡單的說一下。其實就是這個字符在ASCII碼中對應的位置。不信,我們通過一段代碼截圖看看:

技術分享

  在這一幅圖中我們看到中國被傳成了一堆看不懂的鳥文。而英文還是顯示出來了。但是我們通過列表的截取,看出最後一位的c輸出的是99,其實這裏輸出的就是ASCII中c對應的位置,而3個bytes是一個中文,所以我們看到了6段鳥文字,這裏我們就不過多解釋了。

  PS:大家得記得一個東西就是:Python2 裏面的str 就是Python3中的bytes格式,而Python2中的str其實就是Unicode

二、Python3對文件操作補充

  2.1、帶“+”的文件操作:

  在這裏我會說三個,但是其實這些東西都沒有什麽鳥用,只是這算上一個知識點

  r+: 可讀,可以追加
  w+:清空源文件,再寫入新內容
  a+:追加,可以讀

  

f = open(lyrics,r+,encoding=utf-8) #這裏的lyrics是文件名字
f.read()   #我先讀取 
f.write("Leon Have Dream")    #在後面追加
f.close()

  r+:如果是先f.read()再f.write()就是在文件的結尾追加,如果是直接f.write()就直接將文件開始的內容替換成()中的內容;

f = open(lyricsback,w+,encoding=utf-8)
f.read()
f.write("Leon Have Dream")
f.read()
f.close()

  w+:其實就是清空內容再重新寫入write()中的內容,並且f.read()也不會報錯,個人建議可以在快要離職的時候執行這個操作

f = open(lyricsback,a+,encoding=utf-8)
f.read()
f.write("Leon Have A Draem")
f.read()
f.close()

  a+:其實和r+非常相似是在結尾中追加內容,可讀內容

  PS:這裏的補充一下,為什麽在使用r+的時候先執行f.read()再執行f.write()就會在文件的結尾追加和直接使用f.write()直接就替換文件最前邊的內容呢?這是因為Python在讀文件的時候自己維護這一個“指針”,如果我們使用f.read()就相當於讀完了這個文件,這時候指針也就會在最後面了。下面我在補充“f”這個對象的幾個用法來證明Python文件指針。

f = open(lyricsback,r+ ,encoding=utf-8)
print(f.tell()) #this number is 0
f.seek(12) # 將指針向後面移動幾個字節,一個漢字是三個字節
print(f.tell()) # this is seek number
f.write("Love Girl") #這裏就從seek到地方替換
print(f.tell()) # tell()用法就是文件的指針位置
f.close()

  2.2、加b的方式對文件進行操作

  rb:將文件以二進制的方式從硬盤中讀取出來,這裏得記住在open()函數中不要加encoding= 這個參數因為二進制不存在編碼上的問題

  wb:將文件以二進制的方式寫入內容,不過在f.write()中加上encode="utf-8",意思就是申明編碼的格式,並且會清楚原來文件內容

  ab:只能以二進制方式追加。

三、函數

  什麽是函數?函數可以簡單理解一段命令的集合。為什麽需要用函數?這裏有一個非常簡單的原因,比如說你需要對一段代碼反復進行操作,這裏你當然可以一直復制再粘貼,但是這樣靈活性和日後的維護成本將會變大。

#比方說現在需要寫一個報警(調用接口)的程序,這裏就用監控做比喻

if cpu > 80%:
    連接郵箱服務器
    發送消息
    關閉連接

if memery > 80%:
    連接郵箱服務器
    發送消息
    關閉連接

if disk > 80%
    連接郵箱服務器
    發送消息
    關閉連接

#通過寫這樣的一個程序我們發現我們一直在重復調用發送郵箱的這一套接口。這樣我們是否能想出一個辦法解決這樣的重復操作呢?請看下一個版本


發送郵件():
    l連接郵箱服務器
    發送連接
    關閉連接


if cpu > 80%
    發送郵件()

if memery > 80%:
    發送郵件()

....... # 這樣以此類推,我們只需要挑用發送郵件的這個接口就可以節省代碼的發送郵件了

  通過上面的代碼我們發現,我們只需要將報警的這一套流程放到一個公共的地方,等下面觸發報警的條件的時候調用報警的函數,這樣我們就可以省去當每次觸發報警的時候我們自己在寫報警的步驟了。但是函數是怎麽定義呢?又有什麽語法和定義呢?請看下面的一段代碼,其中代碼輸出的是“Leon Have A Dream”

def leon():  #leon是函數名字
    print("Leon Have A Dream")

leon() #調用函數

  帶參數的函數:

a = 10
b = 5

def calc(a,b):  
    print(a ** b)

c = calc(a,b)
print(c)

  首先上面這些代碼執行完會輸出兩個字符,一個是10000,一個是None,為什麽會這樣呢?首先c是等於執行了一遍calc這個函數,所以輸出10000這個數字是肯定的,但是為什麽還會輸出一個None呢?原來我們的“c”執行了儀表calc函數,而calc函數中沒有任何的返回值,所以c == None 。

  PS:函數的返回結果就是return,其中return的含義就是:把函數的執行結果返回給外面,從而讓挑用函數的“對象”得到執行結果

  

  下面我們在看與之相似的列子

a = 10
b = 5

def calc(a,b):
    print(a ** b)

    return a + b

c = calc(a,b)
c = calc(10,6)
print(c)

  首先會輸出的有三個值,分別是100000,1000000,16,為什麽會是這三個呢,下面用一副圖來說一下

技術分享

PS:

形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。函數調用結束返回主調用函數後則不能再使用該形參變量

實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值,輸入等辦法使參數獲得確定值

Python中的全局變量和局部變量

技術分享

PS:函數內部是可以修改列表,字典,集合,實例(class),我們通過下面一個圖來說明

技術分享

  為什麽列表和字典等會被添加和修改呢,原來函數內部知識引用了字典和列表的內存地址,而內存地址無法修改(可以重新開辟一塊內存地址),而每個字典和列表中的每一個值都有對應的內存地址,但是記住我們函數是引用的列表或者字典本身的內存地址,所以這樣打印到出來的也就會跟著改變了。

全局與局部變量

  在子程序中定義的變量稱為局部變量,在程序的一開始定義的變量稱為全局變量。
  全局變量作用域是整個程序,局部變量作用域是定義該變量的子程序。
  當全局變量與局部變量同名時:
  在定義局部變量的子程序內,局部變量起作用;在其它地方全局變量起作用。

位置參數:

技術分享

像上面這樣實參和形參一一對應的上就是就是位置參數

默認參數:

技術分享

在函數將一個位置參數設置成一個默認的值的那一個變量就是默認參數,記住默認參數得在位置參數得後面

關鍵參數:

技術分享

像上面這樣實參和形參不一一對應,並且在調用函數的時候給參數賦值的叫做關鍵參數

非固定函數:

技術分享

通過輸出結果我們發現*args是接收多余的字符串類型的參數,而想Python="simple"(字典)類型的會傳入給**kwargs,這就是非固定參數;當你不知道這個參數需要多少個參數時可以使用該函數類型

遞歸函數——二分查找

a = [1,2,3,4,5,7,9,10,11,12,14,15,16,17,19,21]
def calc(num,find_num):
    print(num)
    mid = int(len(num) / 2)
    if mid == 0:
        if num[mid] == find_num:
            print("find it %s"%find_num)
        else:
            print("cannt find num")
    if num[mid] == find_num:
        print("find_num %s"%find_num)
    elif num[mid] > find_num:
        calc(num[0:mid],find_num)

    elif num[mid] <  find_num:
        calc(num[mid+1:],find_num)
calc(a,12)

技術分享

遞歸的特性

  1. 函數必須有明確的結束(判斷)條件,也就是上圖一開始的mid[0] 不能等於0,因為這樣就會沒有意義了
  2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
  3. 遞歸函數每次向下遞歸一次,上次的函數占用的內存地址不會被釋放,而是一直會被阻塞主,等待函數全部執行完畢後釋放,所以也可以說遞歸是相當消耗內存空間的,對此Python有遞歸的深度,如果超過該深度函數將會被推出(棧溢出)

匿名函數:

calc = lambda x:x+2    #  x是形參,冒號後的內容是該匿名函數執行的動作

print(calc(5))    #匿名函數意識需要通過調用來執行的

calc = lambda x,y,z:x*y*z    #匿名函數可以傳入多個形參,各個參數之間用逗號隔開
print(calc(2,4,6))
c = map(lambda x:x*2,[2,5,4,6])
for i in c:
    print(i)
#三元運算
for i in map(lambda x:x**2 if x >5 else x - 1,[1,2,3,5,7,8,9]):    #lambda最多支持三元運算,map是直接調用匿名函數,但是如果想打印map的內容,需要循環
    print(i) 

高階函數:

def calc(x,y,f):
    print(f(x) + f(y))

calc(10,-10,abs)

高階函數的特性

  1. 把一個函數的內存地址傳給另外一個函數,當做參數
  2. 一個函數把另外一個函數的當做返回值返回

滿足上面的這個兩個特性中的一個就可以稱為高階函數,這裏因為偷懶,就是直接調用了Python中的內置函數

到這裏可以說是第三天的筆記就已經寫完了,其中我覺得後面用到比較多的是高階函數,包括下一個筆記會出現的嵌套函數,匿名函數和遞歸函數相對用的比較少,因為一個是比較消耗系統的內存,另一個也不常用。

Python字符編碼與函數基本使用-day3