binary 代碼 tin warning red all 進制 存儲 ipython

來自猿人學Python教程的學習筆記。 https://www.yuanrenxue.com/

在Python中字符串和unicode真是傻傻分不清楚,在沒搞懂兩個區別時,你會發現程序報的錯怎麽改都是再報錯,讓你煩躁。

學習Python的時候,又重溫了這部分內容,寫了這個學習筆記。

技術分享圖片

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 == ua
Out[1]: True

In [2]: a in ua
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 cant decode byte 0xe7 in position 0: ordinal not in range(128)

# Python3中:

In [1]: a == ba
Out[1]: False

In [2]: a in ba
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-ca907fd8856f> in <module>()
----> 1 a in ba

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]: bT\xe6\x81\xa4

In [21]: a == b
Out[21]: False

In [22]: c = a.encode(gbk)

In [23]: c
Out[23]: bT\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 cant 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。

Python 3 中字符串和 bytes 的區別