关于Python2编码问题的理解

使用Python2处理中文的时候可能会遇到过这样的问题

SyntaxError: Non-ASCII character '\xe4' in file play.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

其中我的代码是这样的

sentence = '你好'

错误信息提示这一行代码中含有非ASCII字符,并且对于这些字符No encoding declared.从错误信息可以看出来Python2默认的编码方式是ASCII。要使用中文需要告诉解释器编码方式是UTF-8。方法是在文件的开头加上# -*- coding: utf-8 -*-.
接下来我又加了一行,目的是想输出句子的长度

sentence = '你好'
print(len(sentence))

此时运行脚本输出的结果是6,而不是2。这其实就涉及到另一个问题,Python2中字符串的存储形式。在Python2中,字符串通常用strunicode两种方式来存储,两者都是basestring的子类。在声明时,类似s='abc'得到的就是str类型的字符串,而s=u'abc'得到的就是unicode类型的字符串。在Python2的内置方法和很多库当中,都是针对unicode来进行操作的。所以在我们的例子中,sentence变量作为一个str类型传给len(),返回结果不是预想中的2。

为了调用Python2中的函数来处理字符串,我们需要实现将str类型的字符串转换成unicode,借助的工具是encode/decode函数。在我们的例子中,进行如下操作

sentence = '你好'
sentence = sentence.decode('utf-8')
print(len(sentence))

运行脚本将会输出2.
如果想将unicode类型转回str类型,执行sentence=sentence.encode('utf-8')即可。或者希望编码成其他形式,比如gbkgb2312,只需要修改编码参数就可以了。

如果我们直接在解释器中操作,会得到以下结果

>>> s = '中文'
>>> s
'\xe4\xb8\xad\xe6\x96\x87'
>>> s = s.decode('utf-8')
>>> s
u'\u4e2d\u6587'
>>> print(s)
中文

为什么sdecode成为unicode之后print(s)还会正常输出呢,这是因为在打印到控制台的时候回自动将unicode编码成控制台支持的编码方式。如果我们人为将其编码方式设置为gbk,将会产生下面的效果

>>> s = s.encode('gbk')
>>> s
'\xd6\xd0\xce\xc4'
>>> print(s)
����

控制台输出了乱码,这是因为s被编码为了gbk格式的,而控制台支持的是utf-8编码。

那么我们其实可以发现,decode/encode配合使用可以实现str编码方式的转变。其实还有一种更简单的方法,直接对str进行encode

# -*- coding: utf-8 -*-
s = '中文'
s = s.encode('gbk')

其实这样做运行起来是会报错的

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

原因是这样的,直接调用str类型的encode函数,它会隐式的首先按照当前的默认编码方式来decodeunicode,然后在encode到指定的编码方式。报错的原因是,默认的编码方式是ascii,无法解析中文。这里的编码和文件头部指定的编码是不一样的,为了不报错,还需要加入

reload(sys)
sys.setdefaultencoding('utf-8')

这样一来代码就可以正常运行了。介绍这一段的目的是,我在网络上看到好多介绍使用sys.setdefaultencoding('utf-8')来解决编码问题的文章,但是都没有讲清楚他的作用,让人把这两行代码的作用和在文件头部指定# -*- coding: utf-8 -*-混淆了。其实在一般情况下还是最好显示的写sentence.decode(...).encode(...)的形式,这样就不涉及sys当前的默认编码了。

本文长期更新,如果我再踩到Python2中编码的坑还会在这里和大家分享 :)

你可能感兴趣的:(关于Python2编码问题的理解)