成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Python高能小技巧:了解bytes與str的區(qū)別

開發(fā) 后端
Python有兩種類型可以表示字符序列:一種是bytes,另一種是str。

 [[388528]]

bytes實(shí)例包含的是原始數(shù)據(jù),即8位的無符號值(通常按照ASCII編碼標(biāo)準(zhǔn)來顯示)。

 

  1. a = b'h\x65llo' 
  2. print(list(a)) 
  3. print(a) 
  4. >>> 
  5. [104, 101, 108, 108, 111] 
  6. b'hello' 

str實(shí)例包含的是Unicode碼點(diǎn)(code point,也叫作代碼點(diǎn)),這些碼點(diǎn)與人類語言之中的文本字符相對應(yīng)。

 

  1. a = 'a\u0300 propos' 
  2. print(list(a)) 
  3. print(a) 
  4. >>> 
  5. ['a''`'' ''p''r''o''p''o''s'
  6. à propos 

 

大家一定要記?。簊tr實(shí)例不一定非要用某一種固定的方案編碼成二進(jìn)制數(shù)據(jù),bytes實(shí)例也不一定非要按照某一種固定的方案解碼成字符串。

  • 要把Unicode數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制數(shù)據(jù),必須調(diào)用str的encode方法。
  • 要把二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成Unicode數(shù)據(jù),必須調(diào)用bytes的decode方法。

調(diào)用這些方法的時(shí)候,可以明確指出自己要使用的編碼方案,也可以采用系統(tǒng)默認(rèn)的方案,通常是指UTF-8(但有時(shí)也不一定,下面就會講到這個問題)。

編寫Python程序的時(shí)候,一定要把解碼和編碼操作放在界面最外層來做,讓程序的核心部分可以使用Unicode數(shù)據(jù)來運(yùn)作,這種辦法通常叫作Unicode三明治(Unicode sandwich)。程序的核心部分,應(yīng)該用str類型來表示Unicode數(shù)據(jù),并且不要鎖定到某種字符編碼上面。

這樣可以讓程序接受許多種文本編碼(例如Latin-1、Shift JIS及Big5),并把它們都轉(zhuǎn)化成Unicode,也能保證輸出的文本信息都是用同一種標(biāo)準(zhǔn)(最好是UTF-8)編碼的。

兩種不同的字符類型與Python中兩種常見的使用情況相對應(yīng):

  • 開發(fā)者需要操作原始的8位值序列,序列里面的這些8位值合起來表示一個應(yīng)該按UTF-8或其他標(biāo)準(zhǔn)編碼的字符串。
  • 開發(fā)者需要操作通用的Unicode字符串,而不是操作某種特定編碼的字符串。

我們通常需要編寫兩個輔助函數(shù)(helper function),以便在這兩種情況之間轉(zhuǎn)換,確保輸入值類型符合開發(fā)者的預(yù)期形式。

第一個輔助函數(shù)接受bytes或str實(shí)例,并返回str:

 

  1. def to_str(bytes_or_str): 
  2.     if isinstance(bytes_or_str, bytes): 
  3.         value = bytes_or_str.decode('utf-8'
  4.     else
  5.         value = bytes_or_str 
  6.     return value  # Instance of str 
  7.  
  8. print(repr(to_str(b'foo'))) 
  9. print(repr(to_str('bar'))) 
  10. >>> 
  11. 'foo' 
  12. 'bar' 

 

第二個輔助函數(shù)也接受bytes或str實(shí)例,但它返回的是bytes:

 

  1. def to_bytes(bytes_or_str): 
  2.     if isinstance(bytes_or_str, str): 
  3.         value = bytes_or_str.encode('utf-8'
  4.     else
  5.         value = bytes_or_str 
  6.     return value  # Instance of bytes 
  7.  
  8. print(repr(to_bytes(b'foo'))) 
  9. print(repr(to_bytes('bar'))) 

 

在Python中使用原始的8位值與Unicode字符串時(shí),有兩個問題要注意。

第一個問題是,bytes與str這兩種類型似乎是以相同的方式工作的,但其實(shí)例并不相互兼容,所以在傳遞字符序列的時(shí)候必須考慮好其類型。

可以用+操作符將bytes添加到bytes,str也可以這樣。

 

  1. print(b'one' + b'two'
  2. print('one' + 'two'
  3. >>> 
  4. b'onetwo' 
  5. onetwo 

 

但是不能將str實(shí)例添加到bytes實(shí)例:

 

  1. b'one' + 'two' 
  2. >>> 
  3. Traceback ... 
  4. TypeError: can't concat str to bytes 

 

也不能將bytes實(shí)例添加到str實(shí)例:

 

  1. 'one' + b'two' 
  2. >>> 
  3. Traceback ... 
  4. TypeError: can only concatenate str (not "bytes"to str 

 

bytes與bytes之間可以用二元操作符(binary operator)來比較大小,str與str之間也可以:

 

  1. assert b'red' > b'blue' 
  2. assert 'red' > 'blue' 

 

但是str實(shí)例不能與bytes實(shí)例比較:

 

  1. assert 'red' > b'blue' 

反過來也一樣,也就是說bytes實(shí)例不能與str實(shí)例比較:

 

  1. assert b'blue' < 'red' 

判斷bytes與str實(shí)例是否相等,總是會評估為假(False),即便這兩個實(shí)例表示的字符完全相同,它們也不相等。例如,在下面這個例子里,它們表示的字符串都相當(dāng)于ASCII編碼之中的foo。

 

  1. print(b'foo' == 'foo'
  2. >>> 
  3. False 

 

兩種類型的實(shí)例都可以出現(xiàn)在%操作符的右側(cè),用來替換左側(cè)那個格式字符串(format string)里面的%s。

 

  1. print(b'red %s' % b'blue'
  2. print('red %s' % 'blue'
  3. >>> 
  4. b'red blue' 
  5. red blue 

 

如果格式字符串是bytes類型,那么不能用str實(shí)例來替換其中的%s,因?yàn)镻ython不知道這個str應(yīng)該按照什么方案來編碼。

 

  1. print(b'red %s' % 'blue'

但反過來卻可以,也就是說如果格式字符串是str類型,則可以用bytes實(shí)例來替換其中的%s,問題是,這可能跟你想要的結(jié)果不一樣。

 

  1. print('red %s' % b'blue'
  2. >>> 
  3. red b'blue' 

 

這樣做,會讓系統(tǒng)在bytes實(shí)例上面調(diào)用__repr__方法,然后用這次調(diào)用所得到的結(jié)果替換格式字符串里的%s,因此程序會直接輸出b'blue',而不是像你想的那樣,輸出blue本身。

第二個問題發(fā)生在操作文件句柄的時(shí)候,這里的句柄指由內(nèi)置的open函數(shù)返回的句柄。這樣的句柄默認(rèn)需要使用Unicode字符串操作,而不能采用原始的bytes。習(xí)慣了Python 2的開發(fā)者,尤其容易碰到這個問題,進(jìn)而導(dǎo)致程序出現(xiàn)奇怪的錯誤。例如,向文件寫入二進(jìn)制數(shù)據(jù)的時(shí)候,下面這種寫法其實(shí)是錯誤的。

 

  1. with open('data.bin''w'as f: 
  2.     f.write(b'\xf1\xf2\xf3\xf4\xf5'
  3. >>> 
  4. Traceback ... 
  5. TypeError: write() argument must be str, not bytes 

 

程序發(fā)生異常是因?yàn)樵谡{(diào)用open函數(shù)時(shí),指定的是'w'模式,所以系統(tǒng)要求必須以文本模式寫入。如果想用二進(jìn)制模式,那應(yīng)該指定'wb'才對。在文本模式下,write方法接受的是包含Unicode數(shù)據(jù)的str實(shí)例,不是包含二進(jìn)制數(shù)據(jù)的bytes實(shí)例。所以,我們得把模式改成'wb'來解決該問題。

 

  1. with open('data.bin''wb'as f: 
  2.     f.write(b'\xf1\xf2\xf3\xf4\xf5'

 

讀取文件的時(shí)候也有類似的問題。例如,如果要把剛才寫入的二進(jìn)制文件讀出來,那么不能用下面這種寫法。

 

  1. with open('data.bin''r'as f: 
  2.     data = f.read() 

 

程序出錯,是因?yàn)樵谡{(diào)用open函數(shù)時(shí)指定的是'r'模式,所以系統(tǒng)要求必須以文本模式來讀取。若要用二進(jìn)制格式讀取,應(yīng)該指定'rb'。以文本模式操縱句柄時(shí),系統(tǒng)會采用默認(rèn)的文本編碼方案處理二進(jìn)制數(shù)據(jù)。

所以,上面那種寫法會讓系統(tǒng)通過bytes.decode把這份數(shù)據(jù)解碼成str字符串,再用str.encode把字符串編碼成二進(jìn)制值。然而對于大多數(shù)系統(tǒng)來說,默認(rèn)的文本編碼方案是UTF-8,所以系統(tǒng)很可能會把b'\xf1\xf2\xf3\xf4\xf5'當(dāng)成UTF-8格式的字符串去解碼,于是就會出現(xiàn)上面那樣的錯誤。為了修正錯誤,需要把模式改成'rb'。

 

  1. with open('data.bin''rb'as f: 
  2.     data = f.read() 
  3.  
  4. assert data == b'\xf1\xf2\xf3\xf4\xf5' 

 

另一種改法是在調(diào)用open函數(shù)的時(shí)候,通過encoding參數(shù)明確指定編碼標(biāo)準(zhǔn),以確保平臺特有的一些行為不會干擾代碼的運(yùn)行效果。例如,假設(shè)剛才寫到文件里的那些二進(jìn)制數(shù)據(jù)表示的是一個采用'cp1252'標(biāo)準(zhǔn)(cp1252是一種老式的Windows編碼方案)來編碼的字符串,則可以這樣寫:

 

  1. with open('data.bin''r', encoding='cp1252'as f: 
  2.     data = f.read() 
  3.  
  4. assert data == 'ñòóôõ' 

 

這樣程序就不會出現(xiàn)異常了,但返回的字符串也與讀取原始字節(jié)數(shù)據(jù)所返回的有很大區(qū)別。通過這個例子,我們要提醒自己注意當(dāng)前操作系統(tǒng)默認(rèn)的編碼標(biāo)準(zhǔn)(可以執(zhí)行 python3 -c 'import locale; print(

locale.getpreferredencoding())'命令查看),了解它與你所期望的是否一致。如果不確定,那就在調(diào)用open時(shí)明確指定encoding參數(shù)。

要點(diǎn)

  • bytes包含的是由8位值所組成的序列,str包含的是由Unicode碼點(diǎn)所組成的序列。
  • 我們可以編寫輔助函數(shù)來確保程序收到的字符序列確實(shí)是期望要操作的類型(要知道自己想操作的到底是Unicode碼點(diǎn),還是原始的8位值。用UTF-8標(biāo)準(zhǔn)給字符串編碼,得到的就是這樣的一系列8位值)。
  • bytes與str這兩種實(shí)例不能在某些操作符(例如>、==、+、%操作符)上面混用。
  • 從文件中讀取二進(jìn)制數(shù)據(jù)(或者把二進(jìn)制數(shù)據(jù)寫入文件)時(shí),應(yīng)該用'rb'('wb')這樣的二進(jìn)制模式打開文件。
  • 如果要從文件中讀取(或者要寫入文件之中)的是Unicode數(shù)據(jù),那么必須注意系統(tǒng)默認(rèn)的文本編碼方案。若無法肯定,可通過encoding參數(shù)明確指定。

 

 

責(zé)任編輯:華軒 來源: 今日頭條
相關(guān)推薦

2021-04-05 22:38:30

Python操作符代碼

2013-10-23 13:10:12

2018-09-17 16:30:24

數(shù)據(jù)庫MySQL小技巧

2020-08-31 10:48:11

MySQL數(shù)據(jù)庫數(shù)據(jù)庫技巧

2018-11-28 12:30:58

Python命令行編程語言

2015-09-08 17:22:03

小娜小冰微軟

2024-04-16 08:24:58

Python_str__()方法字符串

2016-08-05 15:33:26

Python編程異常

2011-09-01 15:22:16

Qt WebKitWebKit

2024-03-26 15:21:43

2024-04-17 09:01:08

Python深拷貝淺拷貝

2022-07-15 15:30:13

Python技巧

2022-06-21 09:02:49

python技巧

2023-10-26 18:03:14

索引Python技巧

2021-05-07 16:02:54

Python代碼優(yōu)化

2021-06-16 10:50:16

Python代碼優(yōu)化

2023-09-07 07:17:01

KubernetesCRI標(biāo)準(zhǔn)

2019-11-20 12:03:42

Python數(shù)據(jù)爬蟲

2017-01-16 15:12:36

Linuxwatch命令命令

2011-06-21 10:02:29

Python
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美成人激情 | 美女天天操 | 成人欧美一区二区三区黑人孕妇 | 国产精品久久久久免费 | 久久涩涩 | 在线国产一区 | 日韩不卡一区二区三区 | 91久久精品 | 久久国产精彩视频 | 久久精品在线 | 亚洲成人一区二区三区 | 国产高清视频 | 日韩精品在线看 | 亚洲精品国产成人 | 国内精品久久久久久影视8 最新黄色在线观看 | 99re99 | 亚洲人久久 | 日韩一二三区视频 | 中文字幕亚洲精品 | 蜜桃在线视频 | 男人天堂99 | 超碰免费在线观看 | 久久99蜜桃综合影院免费观看 | 亚洲视频在线一区 | 超碰在线人人干 | 97国产在线视频 | 免费精品一区 | 久久亚洲视频网 | 亚洲 欧美 日韩在线 | 国产美女高潮 | 久久高清精品 | 95国产精品 | 国产成人亚洲精品自产在线 | 国产欧美精品一区二区三区 | 亚洲精品久久久一区二区三区 | 亚欧精品一区 | 我要看黄色录像一级片 | 美女在线视频一区二区三区 | 精品国产精品三级精品av网址 | 99精品在线观看 | 在线视频一区二区 |