Python——关于中文编码的问题

时间:2023-01-05 09:42:17

事起:一直在用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/