Python2的字符串有两种:str 和 unicode,Python3的字符串也有两种:str 和 bytes。Python2 的 str 相当于 Python3 的bytes,而unicode相当于Python3的str。

Python2里面的str和unicode是可以混用的,在都是英文字母的时候str和unicode没有区别。而Python3 严格区分文本(str)和二进制数据(bytes),文本总是unicode,用str类型,二进制数据则用bytes类型表示,这样严格的限制也让我们对如何使用它们有了清晰的认识,这是很棒的。

Python2 和 Python3 的区别

通过以下代码我们认识以下Python2和Python3的字符串混用情况:

#Python2中:In[1]:'a'==u'a'Out[1]:TrueIn[2]:'a'inu'a'Out[2]:TrueIn[3]:'编程'==u'编程'/usr/local/bin/ipython:1:UnicodeWarning:UnicodeequalcomparisonfailedtoconvertbothargumentstoUnicode-interpretingthemasbeingunequal#!/usr/bin/pythonOut[3]:FalseIn[4]:'编程'inu'编程'---------------------------------------------------------------------------UnicodeDecodeErrorTraceback(mostrecentcalllast)<ipython-input-4-7b677a923254>in<module>()---->1'编程'inu'编程'UnicodeDecodeError:'ascii'codeccan'tdecodebyte0xe7inposition0:ordinalnotinrange(128)#Python3中:In[1]:'a'==b'a'Out[1]:FalseIn[2]:'a'inb'a'---------------------------------------------------------------------------TypeErrorTraceback(mostrecentcalllast)<ipython-input-10-ca907fd8856f>in<module>()---->1'a'inb'a'TypeError:abytes-likeobjectisrequired,not'str'

以上代码可以看到,Python2中str和unicode的在都是ascii码时混用没区别,因为unicode的ascii区域的值跟str的ascii是一样的;而对应非ascii区域(比如中文),二者又不一样了,可以看到Python2抛出了UnicodeDecodeError的异常,相信这也是很多人处理文本时遇到过的错误;‘编程’在str类型时长度是6,而在unicode时是2。不同字符的不同表现,让Python2的str和unicode显得扑朔迷离。

在Python3中,严格区分了str和bytes,不同类型之间操作就会抛出TypeError的异常。

上面用示例阐述了Python2和Python3中字符串的不同,下面主要讲Python3中的字符串。

str和bytes之间的转换

一图胜千言:

str和bytes的相互转换

str.encode(‘encoding’) -> bytes

bytes.decode(‘encoding’) -> str

encoding 指的是具体的编码规则的名称,对于中文来说,它可以是这些值: ‘utf-8’, ‘gb2312’, ‘gbk’, ‘big5’ 等等。

不知道你有没有注意到上图中str矩形要比bytes矩形短,表示同样的内容,str的长度要小于或等于bytes的长度,你可以考虑一下原因(参考Unicode、UTF-8的编码规则)

下面看看具体代码理解一下str和bytes的相互转换:

In[16]:a='T恤'In[17]:aOut[17]:'T恤'In[18]:len(a)Out[18]:2In[19]:b=a.encode('utf8')In[20]:bOut[20]:b'T\xe6\x81\xa4'In[21]:a==bOut[21]:FalseIn[22]:c=a.encode('gbk')In[23]:cOut[23]:b'T\xd0\xf4'In[24]:b==cOut[24]:FalseIn[25]:a==cOut[25]:False

上面str和bytes之间的转换是针对文本内容的,要是其它二进制内容(比如,图片)时,bytes就不能decode成str了,看以下代码的异常:

In[29]:img=open('str-bytes.jpg','rb').read()In[30]:type(img)Out[30]:bytesIn[31]:img.decode('utf8')---------------------------------------------------------------------------UnicodeDecodeErrorTraceback(mostrecentcalllast)<ipython-input-31-c9e28f45be95>in<module>()---->1img.decode('utf8')UnicodeDecodeError:'utf-8'codeccan'tdecodebyte0xffinposition0:invalidstartbyte

因为图片中的二进制数据不符合文本数据的UTF-8编码规则。

上面获得图片数据时,我们用到了open()来读取文件,文件存储的无非是文本和二进制这两种格式,读写文件时也有分清楚编码:

In[32]:open('z.txt','w').write('T恤')Out[32]:2In[33]:open('z.txt','w').write(img)---------------------------------------------------------------------------TypeErrorTraceback(mostrecentcalllast)<ipython-input-33-4a88980b3a54>in<module>()---->1open('z.txt','w').write(img)TypeError:write()argumentmustbestr,notbytesIn[34]:open('z.txt','wb').write(img)Out[34]:12147

读写二进制数据(如图片)时,要加’rb’参数,b代码binary(二进制)

读写文本数据时,一般加’b’,open()会自动转换bytes到str。

总结一下

Python3里面的str是在内存中对文本数据进行使用的,bytes是对二进制数据使用的。

str可以encode为bytes,但是bytes不一定可以decode为str。实际上bytes.decode(‘latin1’)可以称为str,也就是说decode使用的编码决定了decode()的成败,同样的,UTF-8编码的bytes字符串用GBK去decode()也会出错。

bytes一般来自网络读取的数据、从二进制文件(图片等)读取的数据、以二进制模式读取的文本文件(.txt, .html, .py, .cpp等)




文章首发于我的个人博客,同时我也在猿人学网站上写Python教程
你也可以关注我的个人公众号:猿人学Python