频道栏目
首页 > 资讯 > Python > 正文

python字符编码惯用法

17-03-13        来源:[db:作者]  
收藏   我要投稿
  python字符编码惯用法。本文总结在实际应用中遇到的python字符编码问题,制定一套编码相关的约定,避免编码上的错误。

在写猥琐宝典时需要总结soj上做过的题,准备在总结过程中顺便写一个soj上的题解。题解使用python可读,也就是python可以直接eval的格式,以便于处理。写题解老是copy soj上的题目id,title不是太方便,所以就准备自动生成一个空的题解,里面包含了我做过的题。然而直接从soj上只能拿到自己过了的题的id列表,缺乏其它信息。缺乏的信息可以抽象为soj数据库,其中包含了一个以id为主键的表,表中有题目所有的信息。于是代码分为两部分,一部分是soj的工具,其中包含了数据库操作,根据id获取AC的题目列表,另一部分是基于soj工具,负责题解数据的操作。

学python比较晚,当时面临python2和python3的选择,看过一些区别,感觉python3的设计更加合理,而python2比较随意。尤其是字符串部分,python2的概念不清楚,把字节的序列和字符串混在一起,导致一些混乱。首先用python3写的工具,然后想把代码作为web后台,把结果以网页的形式展示出来,这就涉及到python2了,因为在生产环境中还是以python2为主。在转为python2的过程中,不得不重新审视一下字符串的部分,然后总结出这篇文章。

在python2中使用string和unicode string类型,而在python3中则使用bytes和string类型,他们对等:python2.string = python3.bytes, python2.unicode string = python3.string。在python2中,感觉字符串相关东西混乱的原因在于命名失误:以偏概全,用的是string的名表达的是bytes的概念。

bytes的概念:

bytes表达了字节为单位的序列,数据本身的意义很有限,只有当这些数据是按一定规则组织的,进而表达了某个概念,才存在编码问题,数据才有意义。

比如我们可以认为bytes每4字节表示一个32位整数,其中整数每连续8位作为一个字节放在一起,且低位放在前面,这样的bytes就是有编码的,表达了32位整数的概念。

同样的我们也可以认为bytes表示了utf8编码的字符串,每1到6个字节对应一个unicode字符,我们称bytes具有utf8编码,表达了字符串的概念。

string的概念:

如果要表达字符串概念,[Char]才是比较准确的(字符的列表)。至于一个Char占用多少存储,完全不知道。可以是utf16,用2或4字节表示一个Char,也可以是utf32用4字节表达一个Char,还可以是utf8用1到6字节来表示一个Char,这是实现者的事,不应该对我们的使用产生任何影响。

所以,我们需要bytes用来表示string时,需要指定编码,将string转为bytes,对应的函数是encode。当我们认为bytes具有某个字符编码表达的是一个字符串的时候,通过decode并指定该编码得到string。严格地说来在python2中,我们不应该在string对象上调用encode方法,不应该在unicode string对象上调用decode方法。

更进一步,任何抽象都可以encode得到对应的bytes,通过decode得到对应的抽象。

在上述的基础上,引入一些编码约定,目标是避免编码错误。

1.源代码编码,这个编码通过#coding:xxx指出,在python2和python3中概念都很明确。

惯用法(约定):

源代码只使用utf8编码。

2.string literal的类型和编码:

python2中一个形如"xxxx"的string literal具有string类型,编码和源代码编码一致。

而形如u"xxxx"的string literal具有unicode string类型,存在一个自动的源代码编码向unicode string decode的过程。无法转换时会报错,这个时候需要查通过注释指出的编码以及源代码的真实编码。

python3中一个形如"xxxx"的string literal具有string类型,此时,存在自动的源代码编码向unicode的decode过程。

而b"xxxx"的string literal具有bytes类型,表示了源代码的一部分。所以,当其中内容是字符串时,我们也称之是一个和源代码编码一致的字符串。

惯用法:

python2中用string来表达字符串的概念,并使用utf8编码。而python2中unicode string和string混用时,string被认为具有源代码编码,并decode为unicode string。于是存在陷阱,使用的变量的类型失去控制,不知道是string还是unicode string,所以在这里要特别注意。如果用string表达字符串的概念,同时用其它编码,也是可以的,主要是看编码对应的字符集和应用是不是能很好结合在一起。

而python3则string来表达字符串的概念,不关心编码问题。python3不存在混用问题,bytes和string一结合使用,就会报错。

3.urlopen(xxx).read()后的处理:

很明确,这里返回的概念是python3.bytes。

如果确定返回的东西是一个网页的文本,我们可以调用decode(encoding='网页编码', errors='ignore')来得到对应的字符串。

但是,注意2中python2的约定,我们的字符串的类型是python2.string的,所以在python2中我们还要有一个encode的过程:encode(encoding='源代码编码', errors='ignore')

4.写数据文件:

在这里写的是一个特殊的文件,文件可以被看成是一段python代码并执行,所以:

惯用法:

文件编码使用utf8。

在python2中

with open(file, 'wb') as tempf:

tempf.write(data)

with open(file, 'w') as tempf:

tempf.write(data)

都是可以的,因为string无法区别是字节还是字符串。

而在python3中则要使用:

with open(file, 'wb') as tempf:

tempf.write(data.encode(encoding='utf8',errors='ignore'))

with open(file, 'w') as tempf:

tempf.write(data)

因为前者写入的是bytes而后者是string。

上述可行性是建立在我们约定数据文件和源代码编码都是utf8的情况下得到的,如果没有这些约定,我们看看这些代码的语义:

python2中两份代码语义有点乱:

如果已知data是一个字符串,那么第一份代码理论上错误,但是实际上两份代码都完成了把data写到文件,数据文件编码和data一致的目标。

如果已知data是一个二进制流,那么第二份代码理论上错误,但是实际上两份代码也都完成任务,数据文件不存在编码问题。

python3中第一份代码的语义是,写入data这个字符串,数据文件编码是utf8。

而第二份代码语义是:写入data这个字符串,数据文件编码和当前源文件编码(在这是认为默认编码等于当前源文件编码)一致。

5.读数据文件:

惯用法:

在python2中

with open(file, 'rb') as tempf:

tempf.read()

with open(file, 'r') as tempf:

tempf.read()

均可,因为前者返回一些字节,但是用的是string作容器。而后者返回的还是string。

而在python3中则要用:

with open(file, 'rb') as tempf:

tempf.read().decode(encoding='utf8',errors='ignore')

with open(file, 'r') as tempf:

tempf.read()

因为打开的模式不同,前者返回了bytes,后者返回的是string(在内部尝试bytes尝试用源文件encoding解码)。

同样的这些代码的可行性也是建立在若干约定的基础上,如果没有这些约定,也来看看其语义:

python2中第一份代码的语义是读回一些二进制数据。

python2中第二份代码的语义是读入一些字符串。(理论上会有一个先读二进制再根据当前默认编码decode然后再向当前默认编码encode的过程,但是在这里认为两个变换是恒等的,所以没动作。显然,在出现非法字符的情况下,两个变换不恒等。)

python3中第一份代码的语义是读入二进制数据,根据utf8进行decode。

python3中第二份代码的语义是隐式地读入二进制数据,根据当前默认编码进行decode。

在我的应用场景里,读回的数据还有个eval的过程。显然,python2直到eval才可能出现编码错误,而python3能更早发现错误。

相关TAG标签
上一篇:重温java基础
下一篇:管理SQL Server AlwaysOn(1)——基础维护
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站