本節書摘來自華章社群《編寫高品質python代碼的59個有效方法》一書中的第3條:了解bytes、str與unicode的差別,作者[美]布雷特·斯拉特金(brett slatkin),更多章節内容可以通路雲栖社群“華章社群”公衆号檢視
第3條:了解bytes、str與unicode的差別
python 3有兩種表示字元序列的類型:bytes和str。前者的執行個體包含原始的8位值;後者的執行個體包含unicode字元。
python 2也有兩種表示字元序列的類型,分别叫做str和unicode。與python 3不同的是,str的執行個體包含原始的8位值;而unicode的執行個體,則包含unicode字元。
把unicode字元表示為二進制資料(也就是原始8位值)有許多種辦法。最常見的編碼方式就是utf-8。但是大家要記住,python 3的str執行個體和python 2的unicode執行個體都沒有和特定的二進制編碼形式相關聯。要想把unicode字元轉換成二進制資料,就必須使用encode方法。要想把二進制資料轉換成unicode字元,則必須使用decode方法。
編寫python程式的時候,一定要把編碼和解碼操作放在界面最外圍來做。程式的核心部分應該使用unicode字元類型(也就是python 3中的str、python 2中的unicode),而且不要對字元編碼做任何假設。這種辦法既可以令程式接受多種類型的文本編碼(如latin-1、shift jis和big5),又可以保證輸出的文本資訊隻采用一種編碼形式(最好是utf-8)。
由于字元類型有别,是以python代碼中經常會出現兩種常見的使用情境:
開發者需要原始8位值,這些8位值表示以utf-8格式(或其他編碼形式)來編碼的字元。
開發者需要操作沒有特定編碼形式的unicode字元。
是以,我們需要編寫兩個輔助(helper)函數,以便在這兩種情況之間轉換,使得轉換後的輸入資料能夠符合開發者的預期。
在python 3中,我們需要編寫接受str或bytes,并總是傳回str的方法:
另外,還需要編寫接受str或bytes,并總是傳回bytes的方法:
在python 2中,需要編寫接受str或unicode,并總是傳回unicode的方法:
另外,還需要編寫接受str或unicode,并總是傳回str的方法:
在python中使用原始8位值與unicode字元時,有兩個問題要注意。
第一個問題可能會出現在python 2裡面。如果str隻包含7位ascii字元,那麼unicode和str執行個體似乎就成了同一種類型。
可以用+操作符把這種str與unicode連接配接起來。
可以用等價與不等價操作符,在這種str執行個體與unicode執行個體之間進行比較。
在格式字元串中,可以用'%s'等形式來代表unicode執行個體。
這些行為意味着,在隻處理7位ascii的情境下,如果某函數接受str,那麼可以給它傳入unicode;如果某函數接受unicode,那麼也可以給它傳入str。而在python 3中,bytes與str執行個體則絕對不會等價,即使是空字元串也不行。是以,在傳入字元序列的時候必須留意其類型。
第二個問題可能會出現在python 3裡面。如果通過内置的open函數擷取了檔案句柄,那麼請注意,該句柄預設會采用utf-8編碼格式來操作檔案。而在python 2中,檔案操作的預設編碼格式則是二進制形式。這可能會導緻程式出現奇怪的錯誤,對習慣了python 2的程式員來說更是如此。
例如,現在要向檔案中随機寫入一些二進制資料。下面這種用法在python 2中可以正常運作,但在python 3中不行。
發生上述異常的原因在于,python 3給open函數添加了名為encoding的新參數,而這個新參數的預設值卻是'utf-8'。這樣在檔案句柄上進行read和write操作時,系統就要求開發者必須傳入包含unicode字元的str執行個體,而不接受包含二進制資料的bytes執行個體。
為了解決這個問題,我們必須用二進制寫入模式('wb')來開啟待操作的檔案,而不能像原來那樣,采用字元寫入模式('w')。按照下面這種方式來使用open函數,即可同時适配python 2與python 3:
從檔案中讀取資料的時候也有這種問題。解決辦法與寫入時相似:用'rb'模式(也就是二進制模式)打開檔案,而不要使用'r'模式。
要點
在python 3中,bytes是一種包含8位值的序列,str是一種包含unicode字元的序列。開發者不能以>或+等操作符來混同操作bytes和str執行個體。
在python 2中,str是一種包含8位值的序列,unicode是一種包含unicode字元的序列。如果str隻含有7位ascii字元,那麼可以通過相關的操作符來同時使用str與unicode。
在對輸入的資料進行操作之前,使用輔助函數來保證字元序列的類型與開發者的期望相符(有的時候,開發者想操作以utf-8格式來編碼的8位值,有的時候,則想操作unicode字元)。
從檔案中讀取二進制資料,或向其中寫入二進制資料時,總應該以'rb'或'wb'等二進制模式來開啟檔案。