聊聊Python 3 的字串:str 和 bytes 的區別
Python2的字串有兩種:str 和 unicode,Python3的字串也有兩種:str 和 bytes。Python2 的 str 相當於 Python3 的bytes,而unicode相當於Python3的str。
Python2裡面的str和unicode是可以混用的,在都是英文字母的時候str和unicode沒有區別。而Python3 嚴格區分文字(str)和二進位制資料(bytes),文字總是unicode,用str型別,二進位制資料則用bytes型別表示,這樣嚴格的限制也讓我們對如何使用它們有了清晰的認識,這是很棒的。
Python2 和 Python3 的區別
通過以下程式碼我們認識以下Python2和Python3的字串混用情況:
# Python2中: In [1]: 'a' == u'a' Out[1]: True In [2]: 'a' in u'a' Out[2]: True In [3]: '程式設計' == u'程式設計' /usr/local/bin/ipython:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal #!/usr/bin/python Out[3]: False In [4]: '程式設計' in u'程式設計' --------------------------------------------------------------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-4-7b677a923254> in <module>() ----> 1 '程式設計' in u'程式設計' UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 0: ordinal not in range(128) # Python3中: In [1]: 'a' == b'a' Out[1]: False In [2]: 'a' in b'a' --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-10-ca907fd8856f> in <module>() ----> 1 'a' in b'a' TypeError: a bytes-like object is required, not 'str'
以上程式碼可以看到,Python2中str和unicode的在都是ascii碼時混用沒區別,因為unicode的ascii區域的值跟str的ascii是一樣的;而對應非ascii區域(比如中文),二者又不一樣了,可以看到Python2丟擲了UnicodeDecodeError的異常,相信這也是很多人處理文字時遇到過的錯誤;‘程式設計’在str型別時長度是6,而在unicode時是2。不同字元的不同表現,讓Python2的str和unicode顯得撲朔迷離。
在Python3中,嚴格區分了str和bytes,不同型別之間操作就會丟擲TypeError的異常。
上面用示例闡述了Python2和Python3中字串的不同,下面主要講Python3中的字串。
str和bytes之間的轉換
一圖勝千言:
str和bytes的相互轉換
str.encode(‘encoding’) -> bytes
bytes.decode(‘encoding’) -> str
encoding 指的是具體的編碼規則的名稱,對於中文來說,它可以是這些值: ‘utf-8’, ‘gb2312’, ‘gbk’, ‘big5’ 等等。
不知道你有沒有注意到上圖中str矩形要比bytes矩形短,表示同樣的內容,str的長度要小於或等於bytes的長度,你可以考慮一下原因(參考Unicode、UTF-8的編碼規則)
下面看看具體程式碼理解一下str和bytes的相互轉換:
In [16]: a = 'T恤'
In [17]: a
Out[17]: 'T恤'
In [18]: len(a)
Out[18]: 2
In [19]: b = a.encode('utf8')
In [20]: b
Out[20]: b'T\xe6\x81\xa4'
In [21]: a == b
Out[21]: False
In [22]: c = a.encode('gbk')
In [23]: c
Out[23]: b'T\xd0\xf4'
In [24]: b == c
Out[24]: False
In [25]: a == c
Out[25]: False
上面str和bytes之間的轉換是針對文字內容的,要是其它二進位制內容(比如,圖片)時,bytes就不能decode成str了,看以下程式碼的異常:
In [29]: img = open('str-bytes.jpg', 'rb').read()
In [30]: type(img)
Out[30]: bytes
In [31]: img.decode('utf8')
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
<ipython-input-31-c9e28f45be95> in <module>()
----> 1 img.decode('utf8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
因為圖片中的二進位制資料不符合文字資料的UTF-8編碼規則。
上面獲得圖片資料時,我們用到了open()來讀取檔案,檔案儲存的無非是文字和二進位制這兩種格式,讀寫檔案時也有分清楚編碼:
In [32]: open('z.txt', 'w').write('T恤')
Out[32]: 2
In [33]: open('z.txt', 'w').write(img)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-4a88980b3a54> in <module>()
----> 1 open('z.txt', 'w').write(img)
TypeError: write() argument must be str, not bytes
In [34]: open('z.txt', 'wb').write(img)
Out[34]: 12147
讀寫二進位制資料(如圖片)時,要加’rb’引數,b程式碼binary(二進位制)
讀寫文字資料時,一般加’b’,open()會自動轉換bytes到str。
總結一下
Python3裡面的str是在記憶體中對文字資料進行使用的,bytes是對二進位制資料使用的。
str可以encode為bytes,但是bytes不一定可以decode為str。實際上bytes.decode(‘latin1’)可以稱為str,也就是說decode使用的編碼決定了decode()的成敗,同樣的,UTF-8編碼的bytes字串用GBK去decode()也會出錯。
bytes一般來自網路讀取的資料、從二進位制檔案(圖片等)讀取的資料、以二進位制模式讀取的文字檔案(.txt, .html, .py, .c