1. 程式人生 > >不一樣的str,python 3.0 與 python 2.5 的 str 型別比較筆記

不一樣的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
 '測試'