一、coding:utf-8
让我们先来看一个示例,源码文件是utf-8格式:
print('你好 python')
当使用python2执行该程序时会收到一下报错:
File "./hello_world.py", line 2
SyntaxError: Non-ASCII character '\xe4' in file ./hello_world.py on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
错误提示的意思就是存在非ASCII字符,但是却没有encoding declared,同时给了一个连接并说明包含详细原因,这个链接是一个PEP(python enhancement proper)。
这个PEP的内容总结下来就是:
这行代码用于声明代码文件的编码格式,这个信息可以帮助python解析器使用指定的正确编码来解释代码文件。这样就可以允许直接在代码中使用utf-8编码了。
另外需要注意的是:声明的编码格式要和代码文件的格式一样才行,否则会报错。
来看另外一个例子:
# -*- coding:utf-8 -*-
print('你好 python')
将这段代码保存为ANSI格式,并执行,会得到以下报错:
$ python ./hello_python.py
File "./hello_python.py", line 2
SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte
所以说指定编码的时候也不能全部统一指定为utf-8,而是要根据源码文件的格式来指定,两者要一致才行。
另外又在python的官方文档找到一个说明:
意思就是说:默认情况下,python解释器(python2)把源代码文件当做ASCII编码来处理,如果源码文件是其他格式就需要通过一个特殊的注释来说明,也就是:coding:utf-8,当然编码格式支持多中,具体看codecs的支持情况。
这里其实也是由于python诞生的太早了,那时候Unicode都还没有诞生,因此当时作者也只能选择ASCII作为默认的编码格式。python3已经将默认编码格式改为UTF-8
总结
所以总结下来就是,python2中,该行代码的作用是当源代码文件不是ASCII编码时,通过该行代码告诉python解释器正确的编码格式,这样python解释器才能正常解释其中的字符。
另外,由于python3已经修改为默认情况下,将源代码文件当做UTF-8格式来处理,同时我们写代码时现在通常都会使用UTF-8格式来存储,因此python3其实是不用再写这一行代码的,除非你的源代码文件不是UTF-8格式的。
二、sys.setdefaultencoding('utf-8')
先来看一个例子:
# -*- coding:utf-8 -*-
s = '你好'
s.encode('gb2312')
执行以上代码会收到下面的报错:
Traceback (most recent call last):
File "./hello_str.py", line 3, in <module>
s.encode('gb2312')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
第一次遇到这个报错时,感觉很奇怪,明明我做的是encode操作,但是为什么报错确实decode失败呢?
这里就是先提一下了:Python里面的编码和解码也就是unicode和str这两种形式的相互转化。编码是unicode->str,相反的,解码就是str->unicode。
而上面定义的s是str类型的,因此当调用encode时,其实默认是先做了decode,转换为Unicode,然后再执行encode编码为指定的编码的,这里报错的原因就是当做隐式编码、解码时使用的默认格式是:ASCII,但是由于s是utf-8的编码,所以解码就失败了。
解决办法:
1、在文件头部添加sys.setdefaultencoding('utf-8')修改默认的编码、解码格式。
import sys
sys.setdefaultencoding('utf-8')
2、避免由程序做隐式的编码、解码,也就是说要明确str-Unicode的转换规则,但是需要编码时要确认类型是Unicode,如果不是就手动指定正确的解码格式转换为Unicode。
s.decode('utf-8').encode('gb2312')
总结
setdefaultencoding主要在编码、解码没有明确指明编码、解码格式的时候使用。