不一樣的str,python 3.0 與 python 2.5 的 str 型別比較筆記
在2.5中,str型別指的是單字元型別的字串,所以一箇中文字在str中表現為2個位元組,想要生成unicode型別的字串,必須在引號前加入“u”這個標識。
例如:
>>> s = "測試" # 這個是單字元型別的字串
>>> type(s)
<type 'str'>
>>> len(s) # 兩個中文的長度為4個字元
4
>>> s
'/xb2/xe2/xca/xd4'>>> s1 = u"測試" # 這個是unicode型別的字串
>>> type( s1 ) # 使用type可以看到型別
<type 'unicode'>
>>> len( s1 )
4
>>> s1
u'/xb2/xe2/xca/xd4'
注:雖然同樣是4箇中文,但由於在引號前加上了“u”標識,實際上是把兩個中文拆成4個位元組都獨立的unicode字元了,所以我們看到的長度是4,而不是預想中的2。至於怎麼把“s = "測試"”的字串轉成unicode字元,請看後面的說明。
在3.0中,所有的引號裡面的字元預設都是unicode str(雖然使用type的時候顯示的是str),也就是說,3.0中的 str 型別等於2.5的 unicode 型別,而在3.0中存在一個專門用於表示單字元型別字串的類——<class 'bytes'>——即2.5中的 str 型別。
因為在3.0中預設所有字串都是 unicode,因此在3.0中已經不存在“u”的字首標識,也就是說,在2.5中,以下的語法在3.0中是不存在的。
>>> u"測試" # 2.5中,這個能正常執行
u'/xb2/xe2/xca/xd4'>>> u"測試" # 3.0中,這個將會產生一個語法錯誤
SyntaxError: invalid syntax
當然,為了讓我們能在3.0中直接生成單字元字串,在3.0中出現了一個在2.5中不存在的新的語法——在引號前加“b”——b"test string",但需要注意的是,這個語法只適用於英文字元,如果想把它應用到中文字元上,是會產生異常的。
>>> b"test string" # 對於英文字元,一切ok
b'test string'>>> b"測試" # 對於中文字元,語法錯誤
SyntaxError: bytes can only contain ASCII literal characters.
與2.5不同,在3.0中,雖然bytes型別仍然是一個不可修改的例項,但bytes型別不再被視為 string,而是被視為 array of byte,或者說,它更接近於 c 語言中的 char * 型別。
在以下的例子中,我們會發現bytes型別的每一個位元組,都是以 int 的形式表現,而非 str 的形式:
>>> for e in b"test string": print( e, "->", type( e ) )
116 -> <class 'int'>
101 -> <class 'int'>
115 -> <class 'int'>
116 -> <class 'int'>
32 -> <class 'int'>
115 -> <class 'int'>
116 -> <class 'int'>
114 -> <class 'int'>
105 -> <class 'int'>
110 -> <class 'int'>
103 -> <class 'int'>
那麼,我們在3.0中怎麼對 unicode <-> bytes 進行互相轉換呢?答案是用unicode.encode()和bytes.decode()函式。
我們來看看以下的兩個互換的例子:
>>> "測試".encode( "gb18030" )
b'/xb2/xe2/xca/xd4'>>> b'/xb2/xe2/xca/xd4'.decode( "gb18030" )
'測試'
不同於2.5中的 str 和 unicode兩者都存在encode()和decode()方法,在3.0中,str僅有encode()方法,而bytes則僅有decode()方法,這個明顯比2.5更容易讓人理解,而且不象2.5中的 str 和 unicode 那樣讓人容易搞混——很多人一開始的時候都不知道什麼時候應該用encode(),又什麼時候應該decode()。
說起2.5中的str 和 unicode兩者都存在的encode()和decode()方法,如果懂用了確實也能簡化很多複雜的操作,例如我們在一開始就提到的下面的語句:
>>> s1 = u"測試" # 這個是unicode型別的字串
>>> s1
u'/xb2/xe2/xca/xd4'
在這種情況下,得出的這個結果雖然是一個unicode字串,但很顯示它並不是我們想要的東西,因為實際上 s1 是一個長度為4的unicode字串,而非我們原來預想中的長度為2的unicode字串,在這種情況下,我們怎麼轉換成正確的中文字元呢?在2.5中可以用以下的方法:
>>> s1.encode("latin1")
'/xb2/xe2/xca/xd4'
>>> print _
測試
而下面則是一些在2.5中很有意思的用法:
>>> "測試"
'/xb2/xe2/xca/xd4'>>> "測試".encode( "hex" )
'b2e2cad4'>>> 'b2e2cad4'.decode("hex")
'/xb2/xe2/xca/xd4'
但是,在3.0中,由於明確了encode()和decode()的歸屬(用法),所以上面的例子在3.0中肯定是無法使用的,但我們仍然可以在3.0中實現與2.5一樣的效果:
>>> import binascii
>>> "測試".encode( "gb18030" ) # 把“測試”兩字從unicode轉為bytes
b'/xb2/xe2/xca/xd4'
>>> binascii.b2a_hex( _ ) # 把二進位制的bytes轉為可見的ascii字元
b'b2e2cad4'
>>> binascii.a2b_hex( _ ) # 上面行為的逆操作
b'/xb2/xe2/xca/xd4'
>>> _.decode( "gb18030" ) # 再把bytes轉為unicode
'測試'