本文主要介紹在 Python
中 bytes
與 str
的區別。1
Updated: 2022 / 6 / 16
1. Python 有兩種類型可以表示字符序列
bytes
ASCII編碼
標准來顯示)str
Unicode
碼點(code point
,也叫作代碼點),這些碼點與人類語言之中的文本字符相對應a = b'h\x6511o' print(list(a)) # [104, 101, 49, 49, 111] print(a) # b'he11o' a = 'a\\u300 propos' print(list(a)) # ['a', '\\', 'u', '3', '0', '0', ' ', 'p', 'r', 'o', 'p', 'o', 's'] print(a) # a\u300 propos
2.Unicode
數據和二進制數據轉換
Unicode
數據轉換成二進制數據,必須調用 str
的 encode
方法(編碼)FileContent = 'This is file content.'
print(FileContent)
# 'This is file content.'
print(type(FileContent))
# <class 'str'>
FileContent = FileContent.encode(encoding='utf-8')
print(FileContent)
# b'This is file content.'
print(type(FileContent))
# <class 'bytes'>
Unicode
數據,必須調用 bytes
的 decode
方法(解碼)FileContent = b'This is file content.'
print(FileContent)
# b'This is file content.'
print(type(FileContent))
# <class 'bytes'>
FileContent = FileContent.decode(encoding='utf-8')
print(FileContent)
# 'This is file content.'
print(type(FileContent))
# <class 'str'>
調用這些方法時,可以明確指出字符集編碼,也可以采用系統默認的方案,通常是
UTF-8
當前操作系統默認的字符集編碼,
Python
一行代碼查看當前操作系統默認的編碼標准: 在cmd
中執行:python3 -c 'import locale; print(locale.getpreferredencoding())' # UTF-8
3. 使用原始的 8 位值與 Unicode
字符串
使用原始的 8 位值與 Unicode
字符串時需要注意的兩個問題 (該問題等價於使用 bytes
和 str
時需要注意的兩個問題):
bytes
和 str
的互不兼容使用
+
操作符# bytes+bytes print(b'a' + b'1') # b'a1' # str+str print('b' + '2') # b2 # bytes+str print('c' + b'2') # TypeError: can only concatenate str (not "bytes") to str
同類型之間也可以用二元操作符來比較大小
# bytes bytes assert b'c' > b'a' assert b'c' < b'a' # AssertionError print(b'a' == b'a') # True # str str assert 'c' > 'a' assert 'c' < 'a' # AssertionError print('a' == 'a') # True # bytes str assert b'c' > 'a' # TypeError: '>' not supported between instances of 'bytes' and 'str' print('a' == b'a') # False
格式化字符串中的
%s
兩種類型的實例都可以出現在
%
操作符的右側,用來替換左側那個格式字符串(format string
)裡面的%s
。但是如果格式字符串是bytes
類型,那麼不能用str
實例來替換其中的%s
,因為Python
不知道這個str
應該按照什麼字符集來編碼。# bytes % str print(b'red %s' % 'blue' # TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str' # str % bytes print('red %s' % b'blue') # red b'blue' # @ 這樣會讓系統在 bytes 實例上面調用 __repr__ 方法。調用結果替換格式字符串裡的 %s,因此程序會直接輸出 b'blue',而不是輸出 blue
Unicode
字符串操作, 不能使用原始的 bytes
w
模式必須以 ‘文本’ 模式寫入, 否則向文件寫入二進制數據會報錯:# 寫入二進制數據 with open('test.txt', "w+") as f: f.write(b"\xf1\xf2") # TypeError: write() argument must be str, not bytes
wb
可正常寫入二進制數據# 寫入二進制數據 with open('test.txt', "wb") as f: f.write(b"\xf1\xf2")
r
模式必須以 ‘文本’ 模式寫入, 否則從文件讀取二進制數據會報錯:# 讀取二進制數據 with open('test.txt', "r+") as f: f.read() # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte # @以文本模式操縱文件句柄時,系統會采用 默認的文本編碼 方案處理二進制數據。所以,上面那種寫法會讓系統通過 `bytes.decode` 把這份數據解碼成 `str` 字符串,再用 `str.encode` 把字符串編碼成二進制值。然而對於大多數系統來說,默認的文本編碼方案是 `UTF-8`,所以系統很可能會把 `b'\xf1\xf2\xf3\xf4\xf5'` 當成 `UTF-8` 格式的字符串去解碼,於是就會出現上面那樣的錯誤。
rb
可正常讀取二進制數據# 寫入二進制數據 with open('test.txt', "rb") as f: print(b"\xf1\xf2" == f.read()) # True
另一種改法,設置
encoding
參數指定字符串編碼:with open('test.txt', "r", encoding="cp1252") as f: print(f.read())
補充說明:
Python bytes 與 str 的區別︎