在讨论两个版本python间编码区别前,需要理解计算机编码的问题。编码介绍网上有很多资料,不过这里我还是想按照自己的理解说一下。一方面为了文章的完整性,另一方面借此梳理一下编码知识。
计算机中只有0和1,一切都是有二进制表示,包括文本字符。当我们编辑文本"hello world"并保存,计算机首先把文本编码为二进制表示,然后再存储。当我们试图读取刚才保存的文本,首先也是读取二进制数据,然后通过解码,得到文本"hello world"。
上面过程提到的编码方式很多,最早的就是ascii编码,其使用一个8位二进制数可以表示常见的英文字母和符号。ascii码最多表示128个字符(因为规定第一位保留为0)。
ascii码对英语国家够用了,但对非英语国家不够用,比如德语,法语,汉字等字符超过128个,无法仅通过ascii编码解决,因此随后又出现很多其他的编码方式。
文本文件在保存时候,会选择编码方式,因此打开时,要知道其编码方式,用相同的方式解码。否则如果解码方式不一致,会导致乱码。由于互联网出现,需要一种统一编码方式,因此unicode码出现。
需要强调的是,unicode是一个“字符集”,而不是编码方式。它给全球每个字符规定了一个二进制表示,但没说明实际保存文本字符时候应该如何编码。与其对应的编码方式有utf-8,utf-16,utf-32等。最常用的是utf-8编码,16和32可以不考虑。至于utf-8和unicode的关系以及utf-8具体变吗规范,可以参考这个文章http://www.cnblogs.com/xuxyblog/p/4122996.html,里面说的很详细了,我总结一下,拿到一个字符,utf-8编码步骤是:
1、根据unicode字符对应表,得到其unicode码;
2、根据unicode码,确定其需要几个字节表示(1到4个字节);
3、根据字节数,确定其utf-8编码时,可用的编码位;
4、根据可用编码位和unicode码,得到utf-8编码。
现在看一下python2和python3的编码方式:
1、python2中字符类型:
str对象。str对象不是文本字符,当我们定义str对象,计算机会对其编码操作,至于采用什么编码方式,取决于系统。win默认是gbk,linux默认utf-8。比如:
>>> 'china' #定义一个str对象
'china' #这里实际进行了utf-8编码,不过英文字母的utf-8编码和ascii一样的
>>> '中国' #定义一个str对象,中文
'\xe4\xb8\xad\xe5\x9b\xbd' #默认进行utf-8编码
unicode对象。如u'aaa',表示unicode编码的文本字符。可以支持中文等其他非英语字符:
>>> u'中国'
u'\u4e2d\u56fd' #没有进行编码操作,这里显示的是字符的unicode码
python2中还有形如b"hello"的定义方式,它和str对象是一样的。
python2中,unicode和str定义的字节串对象,都有encode和decode,但是不建议使用unicode的decode以及字节串的encode,这是python2的设计缺陷。
>>> u'中国'.encode("utf-8")
'\xe4\xb8\xad\xe5\x9b\xbd' #这里对汉语进行utf-8编码,可以看到结果确实和上面我们直接定义'中国'的结果一致,因为都是 中国 两个字的utf-8编码
当然我们可以采用其他的编码,比如进行utf-16编码:
>>> u'中国'.encode('utf-16')
'\xff\xfe-N\xfdV'
>>> '中国'.decode('utf-8') #这里将str进行utf-8解码,得到 中国 两个字的unicode码
u'\u4e2d\u56fd'
如果进行其他解码会报错,因为unix下默认编码是utf-8
>>> '中国'.decode('gbk')
Traceback (most recent call last):
File "
UnicodeDecodeError: 'gbk' codec can't decode bytes in position 2-3: illegal multibyte sequence
2、python3中两种字符类型:
str对象。str对象本身就是文本字符,是unicode编码,对应于python2中的u'hello'。在python3中,没有形如u'hello'的定义。str可以支持非英语字符:
>>> 'china'
'china'
>>> '中国'
'中国'
bytes对象。bytes是字节串,其对应于python2中的str对象。
字节串和文本字符可以通过encode和decode相互转化
>>> '中国'.encode('utf-8')
b'\xe4\xb8\xad\xe5\x9b\xbd'
>>> b'\xe4\xb8\xad\xe5\x9b\xbd'.decode('utf-8')
'中国'
>>> '中国'.encode('gbk')
b'\xd6\xd0\xb9\xfa'
>>> b'\xd6\xd0\xb9\xfa'.decode('gbk')
'中国'