浅谈 Python 2 中的编码问题

Python 2.x 里的编码实在是一件令人烦躁的事情。不断有初学者被此问题搞得晕头转向。我自己也在很长一段时间内深受其害,直到现在也仍会在开发中偶尔被坑。在本教室的提问和讨论中,编码问题也占据了相当大的比重。

然而这个问题并不能一两句话轻易解答。今天在这里稍微分析一下,希望能帮各位理清这里面的问题。

要弄清编码问题,首先明确几个概念:

str、unicode、encode、decode

str

就是我们通常说的字符串,在 python 中是由引号包围的一串字符。但是 Python 中的默认字符并不包括中文及其他复杂字符(其他非英语语言、特殊符号等)。虽然你可以定义"你好"这样的字符串,但在 Python Shell 中输入一下你就会发现:

>>> '你好'

'\xe4\xbd\xa0\xe5\xa5\xbd'>>>

在程序中,这两个字符是被其他的一些按照某种格式的普通字符所表示。进一步地,输入:

>>> len('你好')

6

字符串的长度也并不是想象中的2。

这就是我们一直说的编码。即通过某种规定的形式,用一些字符表示另一些字符。目的就是为了用少量的简单字符表示更多更复杂的字符。

上述的结果,是因为我的 Python Shell 里默认使用 UTF-8 对字符进行了编码。如果你在 Windows 下进行尝试,会是不一样的结果,因为 Windows 默认使用的是一种叫做 cp936 的编码。

当你需要通过 Python 得到某些输入或者输出,比如读取网页,输出到控制台,读写文件等等,需要处理的都是 str 类型。所以必然逃不过编码的问题。

unicode

为了处理不同编码的字符,于是有了 unicode。unicode 本身是一种编码,因为足够的长度,它可以包容各种文字和符号。同时它也是 Python 中的一种类型。在表示形式上,是字符串的引号前加上一个 u。比如

>>> u'你好'

u'\u4f60\u597d'

>>> type(u'你好')

<type 'unicode'>

>>> type('你好')

<type 'str'>

可以看出,unicode 和 str 是两种不同的类型。

虽然 unicode 很强大,但在 Python 2 中,它不能被直接输出,而必须通过某种编码转成 str。

encode & decode

encode 是 unicode 的一种方法,作用是按照某种形式对其进行编码,转为 str。如:

>>> u'你好'.encode('utf-8')

'\xe4\xbd\xa0\xe5\xa5\xbd'

decode 是 str 的一种方法,作用是按照某种形式对其进行解码,转为 unicode。如:

>>> '你好'.decode('utf-8')

u'\u4f60\u597d'

对 unicode 进行 encode 没太大问题,但对 str decode 时,因为 str 本身是有某种编码的,这时候如果指定的编码不符,就会产生讨厌的乱码:

>>> '你好'.decode('cp936')

u'\u6d63\u72b2\u30bd'

>>> print '你好'.decode('cp936')

浣犲ソ

在默认的 utf-8 编码环境下强行使用 cp936 编码,就会出现乱码。

小结一下就是:

输入 -> str -> decode -> unicode -> encode -> str -> 输出

那么通常问题出在哪里呢?

一般情况下,我们在程序里做的只是

输入 -> str -> 逻辑处理 -> str -> 输出

但在输入输出过程和中间的逻辑处理时,很可能 Python 帮我们默认做了一些 encode 和 decode 的工作。比如说,print 会按照环境的默认形式进行编码,当在需要 unicode 类型的操作而程序拿到的是一个 str 类型是,会使用 ascii 进行解码。前者将可能导致乱码显示,而后者就直接报错。

举两个例子:

1

程序从网上抓取一段网页,中间的文字是 gbk 编码,如 '\xbb\xb6\xd3\xad'(欢迎)。但抓取下来,从默认 utf-8 控制台输出时,就变成了 ��ӭ。同理存在于,Windows 下抓取了 utf-8 编码的网页。正确的处理方法是手动做一次解码:

>>> s = '\xbb\xb6\xd3\xad'

>>> print s

��ӭ

>>> s.decode('gbk')

u'\u6b22\u8fce'

>>> print s.decode('gbk')

欢迎

2

程序有一段从输入得到的 cp936 编码文字,如 '\xd5\xc5\xc8\xfd'(张三),和从数据库取出的 unicode 字符串,如 u'\u597d\u4eba'(好人),两者需要做拼接时:

>>> a = '\xd5\xc5\xc8\xfd'

>>> b = u'好人'

>>> a + b

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

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

抛出了经常发生的 UnicodeDecodeError 异常。这是因为在 str 和 unicode 做 + 操作时,会自动将 str 转成 unicode,并且使用了 ascii 编码。同样的问题也会发生在对一个 str 对象直接使用 encode 的时候。比如:

>>> a = '\xd5\xc5\xc8\xfd'

>>> a.encode('utf-8')

原因也是一样,encode 是 unicode 类型的方法,对 str 进行调用时,程序会默认先直接试图用 ascii 编码把 str 转成 unicode。

正确的做法:

>>> a.decode('cp936') + b

u'\u5f20\u4e09\u597d\u4eba'

>>> a.decode('cp936').encode('utf-8')

'\xe5\xbc\xa0\xe4\xb8\x89'

另外还有个要注意的地方是,Python 代码的 py 文件默认是是用 ascii 编码,所以在程序里有中文的时候,需要在文件开头指定编码,例如:

# coding: utf-8

有些 IDE 比如 PyScripter 会另外设置你的文件编码,有时还会有冲突。

要注意搞清:

程序文件本身的编码 - 你在程序里赋值的字符串

输入来源的编码 - 获取的变量值

输出环境的编码 - 控制台、文件、网页

最好能保证这几个的一致性,不一致时也要做好相应的转换,才能避免掉进编码的坑。

最后,为巴黎恐怖袭击中的遇难者以及所有战争的受害者哀悼。本教室有不少身处国外的读者,各位注意自身安全。愿大家都平安。

(0)

相关推荐

  • 说说你知道的Python3和Python2之间的区别?

    Python是一门语法简洁优美,功能强大无比,应用领域非常广泛,具有强大完备的第三方库的一门强类型的动态,可移植,可扩展,可嵌入的解释型编程语言 编码 Python2中字符的类型: str:已经编码后 ...

  • 浅谈为什么西方油画中塑造的丰腴女人形象看上去却是那么美?

    丰腴,直白地讲,就是有些胖或者微胖的意思. 喜欢油画艺术的朋友不难发现,西方油画中表现女性题材的作品非常多,其中有不少表现的是丰腴的女性形象,以至很多人认为西方人是以胖为美的. 现实中,通常人们多不以 ...

  • 浅谈语言材料中逻辑推理的“还原”

    浅谈语言材料中逻辑推理的"还原" 邓旺林 不少语言材料尤其是说理性语言材料中包含着逻辑推理,而这些逻辑推理大都不像逻辑学教材所概括的那样单纯.完整和规范,难以让人一目了然.因而将其 ...

  • 浅谈信息技术教学中渗透环境教育

    浅谈如何在信息技术教学中渗透环保教育. 泰来县江桥镇中心小学 赵巍 [摘要]环境问题已成为现代社会普遍关心的一个问题,人们越来越清楚地认识到环境教育的重要性.信息技术作为一门技术性学科,在教学中提出环 ...

  • 浅谈钣金行业中的精益生产管理变革

    钣金行业市场竞争已经白热化,市场价格在逐年降低,而制造成本却不断增加,企业的利润空间已经越来越小,如何在这种激烈的竞争环境下立于不败之地,只有向内部要利润.这自然都想到了精益生产,也是很多企业突破瓶颈 ...

  • 浅谈担保司法解释中抵押担保新规定对银行信贷业务的影响

    作者 中国工商银行宁夏分行法律事务部 陈福录 为正确适用民法典有关担保制度的规定,最高人民法院结合民事审判实践,在深入研判.公开征求意见的基础上,并经分析论证,于2020年12月31日发布了<关 ...

  • 浅谈Transformer模型中的位置表示

    作者:哈工大SCIR 徐啸 0. 何为位置信息 首先简单谈一下位置信息.一般将位置信息简单分为绝对位置信息和相对位置信息,并且前者对句子语义的影响不大,更为重要的是后者. 以情感分析 (Sentime ...

  • 吕梁楼承板厂家浅谈多高层建筑中的楼承板

    楼承板是近年来发展很快的领域,这种结构工业化.商品化程度高,施工快,综合效益高,市场需求量很大.接下来,吕梁楼承板厂家与您一起分析:     1.因楼承板可做到大跨度.大空间,分隔使用灵活,而且施工速 ...

  • 浅谈产品结构设计中的改模与修模

    改模与修模是我们产品结构设计中的必不可少的阶段,说的专业点叫设计变更.行业内都说改模和修模. 当一个职场新手进入产品结构设计师这个行业的时候,可能会把改模和修模两个弄混,而且很不严谨的去对待改模与修模 ...

  • 寻龙点穴知识,浅谈形峦中龙脉的十二种形势,以及结穴情况

    龙脉即山脉,包括山脉的走向和起伏变化.因为山脉逶迤起伏如龙形,在形态上多方面与龙相似,故堪舆将山脉比喻做龙.廖瑀在<泄天机·寻龙入式歌>中说:"爱从重浊凝于地,便有高低势.势来起 ...