毫不客气地说,编码真的是 Python 使用者遇到的最多的问题之一。新手看了会崩溃,老手遇到会流泪(感叹以前踩过的坑)。

在踩过很多很多坑之后,已经对这个问题麻木了,反正我现在基本上只用 Python 3 了,问题也比较少了。

Unicode

在讲问题之前先来看两个官方的 HOWTO 文档:Unicode HOWTO Python 2Unicode HOWTO Python 3 。这两篇前面讲的内容基本一致,就是说美国人一开始搞了 ASCII 编码,只有 0 - 127,后来不断增加新的字符,发现 8-bit 不够用了,然后就搞了一种 16-bit 的 Unicode,Unicode 的一种映射方法就是 UTF (Unicode Transformation Format),大家都很熟悉 UTF-8 了。文档后面就分别是 Python 2 和 3 中的 Unicode 了,其他模块也就是 Regex 需要注意一下,Python 2 中匹配的是 ASCII,而 Python 3 中默认是匹配 Unicode,如果需要切换到 ASCII,需要设置 flag=re.A

Python 2

在 Python 2 中编码算是一个老大难的问题了,无数新手栽在这里,想当初搜一下这个问题,博客里面基本都是说在 py 文件的开头加上 # -*- coding: utf-8 -*- 来保平安,如果这么简单就解决了那真是该烧高香了。

encode / decode utf-8

Python 2 默认编码是 ASCII,要使用 Unicode String 还必须写成 u'string' 的形式,真的是非常蛋疼了。

当需要向终端输出字符串,或者将字符串写入文件,或者调用第三方包处理的时候,就可能会遇到编码问题了,这时候通常可以简单的通过 string.encode('utf-8')string.decode('utf-8') 来解决。

sys reload

有时候问题很顽固,有的环境上就是出问题,那就可以考虑在文件开头加上下面这几行,重置运行环境的编码。

import sys
reload(sys)
sys.setdefaultencoding('UTF8')

latin

有时候爬取的网页文本,不管怎么 encodedecode 都总是在报错,这时候可以考虑把 latin 编码当做中间编码,先转 latin 再转 unicode 。还有问题就 ignore

codecs

Python 有专门的 codecs 这么一个包,提供更多编码方面的接口,可以参考官方文档 codecs

Python 3

到了 Python 3 之后编码问题会少很多,但是并不意味着你就可以高枕无忧了。

encoding

为了保证不出问题,读取文件的时候最好明确指定编码方式:

with open('README.md', encoding='utf-8') as f:
readme = f.read()

不要怕麻烦,有时候因为机器或者容器本身的环境,就可能踩到很多坑。

Environment Variable

有时候用 Docker 的时候会遇到这种问题,明明是 Python 3,还指明了 encoding 方式,为什么还出问题呢?通常是因为容器本身的环境变量有问题。

LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8