事起:一直在用spyder进行python程序的编写,今天在添加中文注释的时候,忽然spyder就在命令窗口提示编码问题。
list = [1,2,3,4]
print list # 输出完整列表
首先,给出这个问题的解决方案(solution):
# coding:utf-8
list = [1,2,3,4]
print list # 输出完整列表
直接在头部指明文件的编码方式即可。
事实上,在整个程序运行中只有两处地方有可能出现中文。
1、程序文件当中的静态中文字符:
这个情况下由于python默认是由ascii编码的,无法表示中文。如果我们运行这样的程序,系统提示:SyntaxError: Non-ASCII character ‘\xe8’ in file
所以我们需要做的是告诉系统,程序的编码格式。
关于头部的# coding:utf-8,有以下几个作用
1、如果代码中有中文注释,就需要此声明
2、比较高级的编辑器,会根据头部声明,将此作为代码文件的格式。
3、程序会通过头部声明,解码初始化 u”人生苦短”,这样的unicode对象,(所以头部声明和代码的存储格式要一致)
2、程序运行过程中从文件读取的中文字符:
如果你在python中进行编码和解码的时候,不指定编码方式,那么python就会使用defaultencoding默认编码方式。
而python2.x的的defaultencoding是ascii,这也就是大多数python编码报错:“UnicodeDecodeError: ‘ascii’ codec can’t decode byte ……”的原因。
查询系统默认编码可以在解释器中输入以下命令:
import sys
sys.getdefaultencoding()
关于这个问题,实际上网上有许多解答:
python没办法处理非ascii编码的,此时需要自己设置将python的默认编码,一般设置为utf8的编码格式。
立即停止使用sys.setdefaultencoding()的解决方案
http://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes
1、临时性解决方案:
reload(sys)
sys.setdefaultencoding('utf8')
为什么需要一个看似多余的reload(sys)呢?
先看下python的模块加载过程:
# python -v
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
# /usr/local/lib/python2.6/site.pyc matches /usr/local/lib/python2.6/site.py
import site # precompiled from /usr/local/lib/python2.6/site.pyc
....
Python运行的时候首先加载了site.py,在site.py文件里有这么一段代码:
if hasattr(sys, "setdefaultencoding"):
del sys.setdefaultencoding
在sys加载后,setdefaultencoding方法被删除了,所以我们要通过重新导入sys来设置系统编码.
如果不加reload(sys),会报AttributeError: ‘module’ object has no attribute ‘setdefaultencoding’的错误。
此时在执行sys.getdefaultencoding()就会发现编码已经被设置为utf8的了,但是在解释器里修改的编码只能保证当次有效,在重启解释器后,会发现,编码又被重置为默认的ascii了。
2、一次性修改方案:
在程序中加入:
import sys
reload(sys)
sys.setdefaultencoding('utf8')
3、设置系统默认编码(非常不建议):
一旦代码运行在新环境中,依然会发生错误,比方案2的问题更严重。
在python的Lib\site-packages文件夹下新建一个sitecustomize.py,内容为:
# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
此时重启python解释器,执行sys.getdefaultencoding(),发现编码已经被设置为utf8。
这是因为系统在python启动的时候,自行调用该文件,设置系统的默认编码。
问题的根源:Python2 中的 string
Python 为了让其语法看上去简洁好用,做了很多 tricky 的事情,混淆 byte string 和 text string 就是其中一例。
在 Python 里,有三大类 string 类型,unicode
(text string),str
(byte string,二进制数据),basestring
,是前两者的父类。
其实,在语言设计领域,一串字节(sequences of bytes)是否应该当做字符串(string)一直是存在争议的。我们熟知的 Java 和 C# 投了反对票,而 Python 则站在了支持者的阵营里。其实我们在很多情况下,给文本做的操作,比如正则匹配、字符替换等,对于字节来说是用不着的。而 Python 认为字节就是字符,所以他们俩的操作集合是一致的。
然后进一步的,Python 会在必要的情况下,尝试对字节做自动类型转换,例如,在上文中的 ==,或者字节和文本拼接时。如果没有一个编码(encoding),两个不同类型之间的转换是无法进行的,于是,Python 需要一个默认编码。在 Python2 诞生的年代,ASCII 是最流行的(可以这么说吧),于是 Python2 选择了 ASCII。然而,众所周知,在需要需要转换的场景,ASCII 都是没用的(128个字符,够什么吃)。
在历经这么多年吐槽后,Python 3 终于学乖了。默认编码是 Unicode,这也就意味着,做所有需要转换的场合,都能正确并成功的转换。
推荐解决方案:
所有 text string 都应该是 unicode 类型,而不是 str,如果你在操作 text,而类型却是 str,那就是在制造 bug。
在需要转换的时候,显式转换。从字节解码成文本,用 var.decode(encoding),从文本编码成字节,用 var.encode(encoding)。
从外部读取数据时,默认它是字节,然后 decode 成需要的文本;同样的,当需要向外部发送文本时,encode 成字节再发送。
转载自:http://blog.csdn.net/zuyi532/article/details/8851316
http://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes
参考资料:http://farmdev.com/talks/unicode/