对于Python的字符编码问题也懵了很久,最近做爬虫多次遇到网页转码的问题,干脆彻底解决掉!Just Do it!
1.两种类型str与unicode
str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对 UTF-8编码的str'汉'使用len()函数时,结果是3,因为实际上,UTF-8编码的'汉' == 'xE6xB1x89'。
unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'汉') == 1。
也就是说,str里面是以字节(8位)为单位,一个字符在str里面如何储存取决于其编码方式,从这个意义上讲,str类似于C中的char数组,而unicode类型类似于C++中的string,至于里面具体是如何存储的,可以当做黑盒。
测试一下:
从上面可以看出,print函数输出字符串时,该字符串若有中文,最好用unicode类型。
另外,python中字符串常量的类型为str,前面加u,则类型为unicode。
2.源码编码,外部编码
源码编码
源码编码指的是python脚本源码的编码方式,
源代码文件中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下:
#encoding:utf8声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存。
这点主要体现在源码中出现了中文字符串常量,则常量的编码方式与上方的定义编码相同(也与文件的保存编码相同)。
例1
输出:
例2:
输出:
很直观,当更改了上方的编码后,str内部编码结果也被改变了。
外部编码
外部编码是指当读取文件,获取网页时所获得的str对象其编码方式,比如读取的网页编码方式可能是gbk,读取的文件文本可能是以utf-8方式编码。
4.decode与encode
decode是将str以何种解码为unicode类型;encode是将unicode编码为何种类型str。
decode与encode是str与unicode两种类型间转换的桥梁。
举例如下:
从上图可以看出,python命令界面是以utf-8为默认编码方式,即常量'你好'是以utf-8编码的str对象。
一般而言,
从外部读入str,用decode进行转换unicode类型;
保存至外部文件,将unicode用encode进行编码。
4.默认编码
python2.x中在处理中文时,大多数出现错误的原因所在:python的默认编码,defaultencoding是ascii,看这个例子:
# -*- coding: utf-8 -*- s = "人生苦短" s.encode('gbk')上面的代码会报错,错误信息:UnicodeDecodeError: ‘ascii’ codec can’t decode byte ……
因为你没有指定defaultencoding,所以它其实在做这样的事情:
# -*- coding: utf-8 -*- s = "人生苦短" s.decode('ascii').encode('gbk')设置defaultencoding的代码如下:
reload(sys) sys.setdefaultencoding('utf-8')如果你在python中进行编码和解码的时候,不指定编码方式,那么python就会使用defaultencoding。
比如上一节例子中将str编码为另一种格式,就会使用defaultencoding。
s.encode("utf-8") 等价于 s.decode(defaultencoding).encode("utf-8")再比如你使用str创建unicode对象时,如果不说明这个str的编码格式,那么程序也会使用defaultencoding。
u = unicode("人生苦短") 等价于 u = unicode("人生苦短",defaultencoding)默认的defaultcoding:ascii是许多错误的原因,所以早早的设置defaultencoding是一个好习惯。
5.总结
其实str与unicode应该说是完全不同的两种类型,str作为默认字符串的类型,也是读入外部字符串的默认类型,内部是以字节为单位,类似于C的的char[],而unicode类似于C++中的string类型,是一个类,其内部如何存储,我们并不关心,只需要会调用其接口即可。
尽管这种理解可能不到位,但实际应用应该还是够用...