正文
这是编码系列最后一篇,只讲有关python2的部分。
python2与python3相比有些设定引起了很多莫名其妙的编码问题,我们通常诟病python2在编码方面的坑其实指的就是这部分莫名其妙的问题。
我们通常说的正常的编码问题是上文提到的python3中会遇到的编码问题
-
文件或网页的编码方式和读取时使用的方式不同,这是非常正常的,解决思路也非常清晰,只要使用正确的编码就可以了
-
用
encode
和
decode
方法编码和解码时,使用错误编码造成的错误,这也是找到正确的编码就可以解决
而说python2中的很多编码问题莫名其妙,是因为这些编码解码不是人为指定的,而是经常在你不知道的时候,程序就按照某种编码方式对某些字符进行了编码或解码,而它使用的这种编码方式还不正确,导致了报错或乱码。此时使用者会觉得自己根本没有做编码或解码的工作怎么就会发生编码方面的错误。下面就来大致讲一讲这些问题出现的原因,相信看完上面的基础,理解python2中的问题是非常容易的。
这些莫名其妙的编码问题主要是由两个默认编码造成的
-
py2中默认编码方式是ASCII,py3是UTF-8(这个默认编码在什么时候会遇到后面会讲),这个是引起编码问题的主要原因
-
py2中用
a='中文'
定义的字符串其实不是真正的字符串,它不是Unicode,所以说在定义
a
时默认进行了一次编码转换,这个编码转换和上面的ASCII还没有关系,使用的是另一种默认的编码
上那两个默认编码在python3中几乎不会用到,它们产生的原因在于pyhton2设计上的缺陷,下面就列一下python2是如何导致的编码错误,一共5种错误。
1.定义str时的自动编码
在python2中,
a='中文'
这个
a
不是Unicode,
b=u'中文'
这个b才是。而在python3中根本没有
u'中文'
这一说,
a='中文'
这个a就是Unicode。
准确地说,a叫字节串,b才叫字符串(前面提到过Unicode和字符串完全等同)。a其实是一个二进制字节流,是字符串encode后的产物。所以说在
a='中文'
这个赋值过程中,默认进行了一次编码encode,将’中文’这个字符串编码成了二进制数。
既然是编码,肯定是按照某一套编码方式来做的。这个编码方式再不同场景是不一样的。用下面代码查看当前默认编码是什么
import locale
locale.getdefaultlocale()
这就是两种默认编码中的第二种。
一般在windows命令行下结果是
('zh_CN', 'cp936')
,即使设置了chcp 65001,或者在jupyter中使用也是一样是cp936。
说明定义字符串(准确来说应该叫字节串)时,在windows下都会默认用GBK进行编码。
字符串的两种定义方式会让使用者产生混乱,更容易触犯到后面的那些雷区。
解码时如果不能理解它原来是怎么编码的就会使用错误的编码从而造成报错。
2.str和unicode混用造成的错误
由于第一条中的差异,
a='中文'
这样定义的a在编码和解码方面也与py3是有不同的。
-
在python3中,这样定义的a只能encode,因为它是Unicode
-
在python2中,这个a主要是要decode,因为它是编码过的
从这一点中,第一种默认编码上场了。
如果str和unicode混用,比如
'中文'+u'好'
,这个过程会默认将str解码成unicode,使用的是py2默认的ASCII编码,而中文不对应ASCII编码,于是报错。这是第一种默认编码产生错误的第一种,之后还有很多地方都会有类似的默认转换。
在这里首先说一下如何查看这个默认编码是什么
import sys
sys.getdefaultencoding()
就是这个命令,在py2中结果是
ascii
,在py3中就是
utf-8
。涉及到的两个默认编码都出现了,查看命令也不一样,注意区分。
另外再说一下关于这点python3是怎么设计的。如果str和bytes直接相加,会直接报出一个错误
TypeError: Can't convert 'bytes' object to str implicitly
,python3说的很明确不能隐式转,而不是像python2一样偷偷给你转了。