1. 程式人生 > 其它 >python 修改bytes只_瞭解Bytes、Str、Unicode三者之間的關係

python 修改bytes只_瞭解Bytes、Str、Unicode三者之間的關係

技術標籤:python 修改bytes只

(文章寫的有點亂,湊合看吧)

在Python 3中有兩種表示字串的方式:bytes和str。bytes的例項包含原始的8位值(raw 8-bit values);str例項包含Unicode字元。

Python 2中也有兩種表示字串的方式:str和unicode。與Python 3對比,Python 2中str例項包含原始的8位值,unicode包含Unicode字元。

有很多種方式能夠將Unicode字元表示為二進位制資料(binary data,raw 8-bit values)。最常用的一種編碼格式是UTF-8。需要注意的是,Python 3中的str例項以及Python 2中的unicode例項都沒有相關的二進位制編碼格式。要想使Unicode字元轉換成二進位制資料必須使用encode方法。要想使二進位制資料轉換成Unicode字元必須使用decode方法。

c172a31f5645c4eed8147544406ae0d8.png

Python 3程式碼示例:

1e211a36023e20e65a2139ce722a8f89.png

當你在編寫Python程式時,最好在遠離介面的地方進行decode、encode操作。程式碼的核心應該使用Unicode字元型別(Python 3中使用str,Python 2中使用unicode),並且不應當對任何字串進行encode操作。這樣做的好處就是,當你需要嚴格控制你的輸出文字的編碼格式時,你的程式碼可以很容易的轉換成其它字元編碼格式,例如latin-1、Shift JIS、 Big5等。Python針對字元型別的分類引出了兩種問題:

  • 按照8位原始值的形式操作UTF-8字串或者其它編碼格式字串;
  • 操作Unicode字元。

此時你需要一些幫助方法來幫助你修改方法的輸入引數,使這些引數的編碼格式符合你的要求。

在Python 3中你需要一個方法接收str或bytes,返回str:

077ac5e230cd8f4568a450616d35e2f9.png

同時需要另一個方法接收str或者bytes返回bytes:

64e0356c502a39f58c5bd87a44abcc0a.png

在Python 2中你需要一個方法,這個方法接收str或unicode,返回unicode:

def to_unicode(unicode_or_str): if isinstance(unicode_or_str, str): value = unicode_or_str.decode('utf-8') else: value = unicode_or_str return value # Instance of unicode

同時需要另一個方法用於接收str或者unicode,返回str:

def to_str(unicode_or_str): if isinstance(unicode_or_str, unicode): value = unicode_or_str.encode('utf-8') else: value = unicode_or_str return value # Instance of str

在Python中處理原始8位值和Unicode字元時有兩個大問題。

第一個問題是在Python 2中,如果一個字串只包含7位的ACSII字元時,str和unicode例項看起來是一樣的。

  • 可以使用+連結兩個str和unicode物件;
  • 可以使用等於、不等於操作符比較兩個str和unicode物件;
  • 可以使用unicode例項作為格式化字串,例如"%s"。

上面的行為意味著不論一個方法期望接收的是str還是unicode物件,你都可以隨意傳遞這兩個中的一個。在Python 3中,bytes和str從來都不是一回事,甚至空物件也不一樣,所以在傳遞字元序列時一定要注意所傳遞的資料型別。

另一個問題是,在Python 3中檔案處理方法返回的物件(open方法返回的物件)預設是使用UTF-8編碼的。在Python 2中檔案操作預設返回二進位制編碼(binary encoding)。這會導致一些奇怪的問題,尤其是那些習慣於Python 2的程式設計師。

例如,想要向檔案中寫入一些隨機的二進位制資料,Python 2就可以實現,但是Python 3就會出現異常。

with open('/tmp/random.bin', 'w') as f: f.write(os.urandom(10))>>>TypeError: must be str, not bytes

出現這個錯誤的原因是因為在Python 3中open方法增加了一個encoding引數。這個引數的預設值是UTF-8,這使得open方法返回物件的read和write方法都是使用包含unicode字元的str物件而不是使用bytes資料。

要想使read、write工作正常,你必須指定檔案是按照二進位制寫(wb)模式開啟的,而不是簡單的使用寫(w)模式。修改上面程式碼,使用"wb"預設就可以同時在Python 2和Python 3中正常執行了:

with open('/tmp/random.bin', 'wb') as f: f.write(os.urandom(10))

同樣的問題也會出現在read方法中,解決方法是一樣的,修改檔案開啟模式,使用"rb"。

總結:

  • 在Python 3中,bytes包含8位序列值,str包含unicode字元序列。 bytes和str例項不能一起使用(比如, > 或 +);
  • 在Python 2中,str包含8位序列值,unicode包含unicode字元序列。當str僅包含7位ACSII字元時,str和unicode例項可以一起使用;
  • 使用heler方法來保證輸入的字串是你希望的型別 (如:8位值序列、UTF-8字串、Unicode字串等);
  • 如果想從檔案讀或者寫二進位制資料,一定要使用二進位制形式開啟檔案(“rb”或者"wb")。