字符串編碼
python3和python2的一個主要差異就在于字符編碼,在python2中聲明的字符串默認(rèn)是bytes
字節(jié)流,而在python3中聲明的字符串默認(rèn)是unicode
字符串,我們用以下代碼進(jìn)行示例:
# if using python2
str_raw = "我們愛編程"
str_bytes = b"我們愛編程"
str_unicode = u"我們愛編程"
print(str_raw) # 輸出 '我們愛編程'
print(str_bytes) # 輸出 '我們愛編程'
print(str_unicode) # 輸出 '我們愛編程'
print(type(str_raw)) # 輸出 <type 'str'>
print(type(str_bytes)) # 輸出 <type 'str'>
print(type(str_unicode)) # 輸出 <type 'unicode'>
# if using python3
str_raw = "我們愛編程"
str_bytes = b"我們愛編程" # 會報(bào)錯 SyntaxError: bytes can only contain ASCII literal characters.
str_bytes = b"we love programming" # 輸出 b'we love programming'
str_unicode = u"我們愛編程"
print(str_raw) # 輸出 '我們愛編程'
print(str_unicode) # 輸出 '我們愛編程'
print(type(str_raw)) # 輸出 <class 'str'>
print(type(str_unicode)) # 輸出 <class 'str'>
print(type(str_bytes)) # 輸出 <class 'bytes'>
從這個例子中,我們知道在python2中聲明的字符串默認(rèn)是以bytes
的形式存儲的,如果用交互式終端去打印python2的字符,那么會顯示如下
>>> str_raw = "我們愛編程"
>>> str_raw
'\xe6\x88\x91\xe4\xbb\xac\xe7\x88\xb1\xe7\xbc\x96\xe7\xa8\x8b'
而python3中聲明的字符串默認(rèn)以unicode
形式儲存,如果用交互式終端去打印的話,那么顯示如下:
>>> str_raw = "我們愛編程"
>>> str_raw
'我們愛編程'
這里需要提一嘴的是,unicode是字符集的編碼,而utf-8是unicode的其中一種編碼實(shí)現(xiàn)(此外還有utf-16等)。然而unicode作為一種能包含100萬符號以上的字符集,其編碼存在一定的冗余,比如嚴(yán)的 Unicode 是十六進(jìn)制數(shù)4E25,轉(zhuǎn)換成二進(jìn)制數(shù)足足有15位(100111000100101),不利于數(shù)據(jù)持久化保存和傳輸,因此需要編碼成字節(jié)流bytes進(jìn)行儲存或者網(wǎng)絡(luò)傳輸,關(guān)于字符編碼和字符集的擴(kuò)展知識可見[1]。如Fig 1.1所示,在python3中稱bytes -> unicode的過程為解碼,而unicode -> bytes的過程為編碼,數(shù)據(jù)類型而言,在python3中的<class 'str'>其實(shí)對應(yīng)python2的<type 'unicode'>,python3的<class 'bytes'>對應(yīng)python2的<type 'str'>。對于函數(shù)而言,python3的bytes()對應(yīng)python2的str(),python3的str()對應(yīng)python2的bytes()。相對應(yīng)的,對于python3而言的解碼對于python2而言是編碼,對于python3而言的編碼則是python2的解碼。
總而言之,在python中推薦一切字符處理都轉(zhuǎn)換成unicode后進(jìn)行處理,需要持久化或者傳輸時候在編碼成字節(jié)流進(jìn)行后續(xù)操作。
Fig 1.1 python3中字符串的編碼與解碼。
Reference
[1]. https://zhuanlan.zhihu.com/p/38333902, 字符編碼那點(diǎn)事:快速理解ASCII、Unicode、GBK和UTF-8