Python 编码小结
1. 相关概念说明:
字符是个抽象的概念,在 Python 中字符串都是用 Unicode 表示的,那些形如 ‘abcd’ 这样常见的形式,我在这里把它称为字节串(字节序列)以示区别。当我们面对一串字节时,如果我们不知道编码方法,我们根本不知道该如何解释眼前的这些字节组成的序列。
本文中我们用 str 表示字节串,uni 表示 unicode 字符串
2. Python 内部处理字节串时的隐式转换
Python 中有好多处理字符串的函数,它们几乎都可以接受字节串和 Unicode 字符串。当传入的参数是字节串时,Python 会先用默认的 ASCII 编码将这串字节转换成对应的 Unicode 字符串,然后再使用相应的函数进行处理,因此当字节序列中,出现码值大于 127的字节时,解码就会出错:
>>> s.find('Was\x9f')
Traceback (most recent call last):
...
UnicodeDecodeError: 'ascii' codec can't decode byte 0x9f in position 3: ordinal not in range(128)
>>> s.find(u'Was\x9f')
-1
那么如何判断一个字符串到底是字节序列还是 unicode 呢?从外观上可以这样判断,凡是字符串引号前面没有加 ‘u’的都是字节串,加了 ‘u’的是 Unicode 字符串。
In [1]: t = '中文'
In [2]: type(t)
Out[2]: str
In [3]: t = u'中文'
In [4]: type(t)
Out[4]: unicode
用代码可以这样判断:
In [5]: def is_unicode(string):
...: return isinstance(string, unicode)
...:
In [6]: is_unicode('中文')
Out[6]: False
In [7]: is_unicode(u'中文')
Out[7]: True
3. 一般处理流程
在 Python 中字符串都是用 Unicode 表示的,所以当我们要对这些字符串进行存储或者传输时,就需要对这些字符进行适当的编码,使这些字符串转换成适合存储和传输的字节序列。因此典型的处理流程是这样的:
文件读取或键盘输入的字节序列 ---(解码)---- 适合Python 程序使用的 Unicode 字符串 -----(编码)---- 适合存储或传输的字节序列形式
用符号可以这样表示:
str -> decode('the_coding_of_str') -> unicode # 字节串解码得到 Unicode
unicode -> encode('the_coding_you_want') -> str # Unicode 编码得到字节串
不同编码之间的转换,需要使用 Unicode 字符串作为转换的中间格式, 转换流程如下:
str.decode('the_coding_of_str').encode('the_prefered_coding_of_str')
encode 和 decode 函数使用须知,字节串调用encode 或者 Unicode 调用decode都会引起隐式转换:
str.encode('xxx') -----> str.decode('ascii').encode('xxx')
uni.decode('xxx') ------> uni.encode('ascii').decode('xxx')
这样,只要字节串中码值大于 127 或者 Unicode 中字符的代码点的值大于 127 就会抛出,UnicodeDecodeError 或 UnicodeEncodeError。所以避免错误的一个原则是:字节串尽量不使用 encode函数,unicode 尽量不要使用 decode 函数。