Effective Python bytes 與 str 的區(qū)別
1、Python 有兩種類型可以表示字符序列
bytes:實例包含的是 原始數(shù)據(jù) ,即 8 位的無符號值(通常按照 ASCII 編碼 標準來顯示)str:實例包含的是Unicode碼點(code point,也叫作代碼點),這些碼點與人類語言之中的文本字符相對應(yīng)
a = b'h\x6511o' print(list(a)) print(a) a = 'a\\u300 propos' print(list(a)) print(a) # 輸出結(jié)果 [104, 101, 49, 49, 111] b'he11o' ['a', '\\', 'u', '3', '0', '0', ' ', 'p', 'r', 'o', 'p', 'o', 's'] a\u300 propos
2、Unicode 數(shù)據(jù)和二進制數(shù)據(jù)轉(zhuǎn)換
- 把
Unicode數(shù)據(jù)轉(zhuǎn)換成二進制數(shù)據(jù),必須調(diào)用 str 的encode方法(編碼) - 把二進制數(shù)據(jù)轉(zhuǎn)換成
Unicode數(shù)據(jù),必須調(diào)用 bytes 的decode方法(解碼) - 調(diào)用這些方法時,可以明確指出字符集編碼,也可以采用系統(tǒng)默認的方案,通常是 UTF-8
3、使用原始的 8 位值與 Unicode 字符串
使用原始的 8 位值與 Unicode 字符串時需要注意的兩個問題:
- 該問題等價于:使用
bytes和str時需要注意的兩個問題
3.1 問題一:bytes 和 str 的實例互不兼容
使用 + 操作符:
# bytes+bytes
print(b'a' + b'1')
# str+str
print('b' + '2')
# 輸出結(jié)果
b'a1'
b2
bytes + bytes,str + str都是允許的- 但
bytes + str會報錯
#
bytes+str
print('c' + b'2')
# 輸出結(jié)果
print('c' + b'2')
TypeError: can only concatenate str (not "bytes") to str
同類型之間也可以用二元操作符來比較大小
assert b'c' > b'a' assert 'c' > 'a'
但 bytes 和 str 之間用二元操作符也會報錯
assert b'c' > 'a'
# 輸出結(jié)果
assert b'c' > 'a'
TypeError: '>' not supported between instances of 'bytes' and 'str'
判斷 bytes 與 str 實例是否相等
兩個類型的實例相比較總會為 False,即使字符完全相同
# 判斷 str、bytes
print('a' == b'a')
# 輸出結(jié)果
False
格式化字符串中的 %s
兩種類型的實例都可以出現(xiàn)在 % 操作符的右側(cè),用來替換左側(cè)那個格式字符串(format string)里面的 %s
但是!如果格式字符串是 bytes 類型,那么 不能 用 str 實例來替換其中的 %s ,因為 Python 不知道這個 str 應(yīng)該按照什么字符集來編碼
# %
print(b'red %s' % 'blue')
# 輸出結(jié)果
print(b'red %s' % 'blue')
TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str'
但是!反過來卻可以,如果格式字符串是 str 類型,則 可以 用bytes 實例來替換其中的 %s,但結(jié)果可能不是預(yù)期結(jié)果
# %
print('red %s' % b'blue')
# 輸出結(jié)果
red b'blue'
這樣會讓系統(tǒng)在 bytes 實例上面調(diào)用 __repr__ 方法
調(diào)用結(jié)果替換格式字符串里的 %s,因此程序會直接輸出 b'blue',而不是輸出 blue
3.2問題二:操作文件句柄時需要使用 Unicode 字符串操作
不能使用原始的 bytes
向文件寫入二進制數(shù)據(jù)會報錯:
# 寫入二進制數(shù)據(jù)
with open('test.txt', "w+") as f:
f.write(b"\xf1\xf2")
# 輸出結(jié)果
f.write(b"\xf1\xf2")
TypeError: write() argument must be str, not bytes
- 報錯是因為
w模式必須以 文本 模式寫入 - 將模式改成
wb即可正常寫入二進制數(shù)據(jù)
with open('test.txt', "wb") as f:
f.write(b"\xf1\xf2")
讀取文件中二進制數(shù)據(jù)
with open('test.txt', "r+") as f:
f.read()
# 輸出結(jié)果
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte
- 報錯是因為 r 模式必須以 文本 模式讀取
- 以文本模式操縱文件句柄時,系統(tǒng)會采用 默認的文本編碼 方案處理二進制數(shù)據(jù)
- 所以,上面那種寫法會讓系統(tǒng)通過
bytes.decode把這份數(shù)據(jù)解碼成 str 字符串,再用str.encode把字符串編碼成二進制值 - 然而對于大多數(shù)系統(tǒng)來說,默認的文本編碼方案是
UTF-8,所以系統(tǒng)很可能會把b'\xf1\xf2\xf3\xf4\xf5'當(dāng)成 UTF-8 格式的字符串去解碼,于是就會出現(xiàn)上面那樣的錯誤
將模式改成 rb 即可正常讀取二進制數(shù)據(jù):
with open('test.txt', "rb") as f:
print(b"\xf1\xf2" == f.read())
# 輸出結(jié)果
True
另一種改法,設(shè)置 encoding 參數(shù)指定字符串編碼:
with open('test.txt', "r", encoding="cp1252") as f:
print(f.read())
# 輸出結(jié)果
ñò
這樣也不會有異常了
需要注意:當(dāng)前操作系統(tǒng)默認的字符集編碼,Python 一行代碼查看當(dāng)前操作系統(tǒng)默認的編碼標準
在 cmd 中執(zhí)行:
> python3 -c 'import locale; print(locale.getpreferredencoding())' UTF-8
到此這篇關(guān)于Effective Python bytes 與 str 的區(qū)別的文章就介紹到這了,更多相關(guān)Python bytes 與 str 的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python爬蟲中urllib庫的進階學(xué)習(xí)
本篇文章主要介紹了Python爬蟲中urllib庫的進階學(xué)習(xí)內(nèi)容,對此有興趣的朋友趕緊學(xué)習(xí)分享下。2018-01-01
使用Python實現(xiàn)Oracle數(shù)據(jù)庫自動巡檢程序
這篇文章主要為大家詳細介紹了如何創(chuàng)建一個Oracle數(shù)據(jù)庫自動巡檢程序,以確保數(shù)據(jù)庫的順暢運行,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
詳解使用django-mama-cas快速搭建CAS服務(wù)的實現(xiàn)
這篇文章主要介紹了詳解使用django-mama-cas快速搭建CAS服務(wù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
django admin search_fields placeholder 管理后臺添加搜索框提示文字
這篇文章主要介紹了django admin search_fields placeholder 管理后臺添加搜索框提示文字,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

