python编码问题,从隐隐作痛到除去病根
查阅的资料链接
python源文件默认编码与内部默认编码
源文件默认编码
1.源文件默认编码为ASCII,所以,如果不显示声明当前代码用什么编码写的,python会用ASCII去解析,如果源文件中有UTF-8编码,由于ASCII不能翻译UTF8编码,则会报错了.
#file test.py 使用UTF8保存 a='a' b='好'
运行后
SyntaxError: Non-ASCII character '\xe5' in file test.py on line 2, but no encodi ng declared; see http://python.org/dev/peps/pep-0263/ for details
上面报错说character '\xe5'是非ASCII码,因为'\xe5'是'好'的UTF8字节串的一部分
如下
在编码为UTF8的终端中打印'好' >>> a='好' >>> a '\xe5\xa5\xbd
所以,当前的源文件是什么编码编辑的,一定要声明出来.比如
#coding=utf-8 #先在这里声明a='好'
print a
这点python就不如php先进了,php在配置文件php.ini中已经默认指定了编码格式,从而无需在文件中指出(除非有需要)。
以上代码运行结果为
E:\qprwork\Edit_laravel\qingpr_python_task>python test.py
濂
发现乱码了,因为我的cmd终端编码为GBK,而我的脚本是用UTF8写的,cmd认不出来啦,该怎么办呢?
我有以下几种解决方案
方案1.调整终端默认编码,这点依个人需求来吧。
方案2.让脚本迎合终端的口味,要么方案a:脚本就保存为GBK的,要么方案b:在需要终端显示的地方转一下码,我说下b方案
#coding=utf-8
import sys
a='好'
#这个文件是保存为UTF8编码,如果要在cmd上正常显示,需要转为GBK,
aUnicode = a.decode('utf-8') #先解码为unicode,解码的时候要告诉python,a是一个utf8字节串,不要又以为是ASCII字节串
aGBK=aUnicode.encode('GBK')#将unicdode编码的a再编码为GBK
print aGBK
以上有一个小插曲,我直接用a.encode('GBK')行吗?这样是不行的,因为编码(encode)是针对unicode而言的,必须对unicode编码,如果硬生生使用类似'我'.encode('GBK'),则会报错的
如下
>>> a='好'
>>> a.encode('GBK')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xba in position 0: ordinal
not in range(128)
>>>
看到了吧,python抛出了Unicode解码异常,python又说'ascii'怎么怎么样,为啥啊?
因为python只会对unicode字符串进行encode,如果非要对字节串encode,则它会先把字节串decode,以下是伪代码
a.encode('GBK')==( a.decode('默认编码').encode('gbk') )
上面的unicode解码异常,也是在进行解码的时候抛出的,python认为a就是用默认编码,即ASCII编码的,可a是UTF8编码啊,'好'在ASCII中不存在,所以会报错
方案3.我不管你终端什么编码,终端你都要给我正常显示.
那就用最直接的unicode编码啦,让python自己根据系统的当前编码进行转码打印出来
#coding=utf-8 print u'我'
当 print 一个unicode字符串时,打印出来的是unicode对应的系统编码的字符,从而不会乱码了
衍生的一个小问题,我就是想看某变量unicode是啥样的,那就用reper函数(返回一个对象的字符串形式)
>>> a=u'好'
>>> a
u'\u597d'
>>> print repr(a)
u'\u597d'
和php做个比较,在命令行中运行php文件时,比如cmd中运行编码为UTF8的文件,即使是多字节字符,也不会乱码,我猜测这是因为php在输出内容给终端时,php内部对终端编码有检测和转换机制,这点python2.7并没有做到。python2.7很实诚,文件什么编码,我给终端就是什么编码。
内部默认编码
在终端的命令行模式编辑代码时,不需要再声明当前写代码时所用的编码,我猜是因为python在命令行模式时,直接读取当前系统的编码
例如,windows的cmd下再查看'好'这个字
在编码为GBK的终端(cmd)打印'好' >>> a='好' >>> a '\xba\xc3'
可以看到在cmd中,'好'是两个字节,
linux的shell中
在编码为UTF8的终端中打印'好' >>> a='好' >>> a '\xe5\xa5\xbd
linux的shell环境,默认编码为utf8,‘好’是三个字节
需要注意的地方
python内部默认编码为ASCII,导致使用一些函数时需要注意,比如str和unicode
str函数,以字符串的形式返回对象的呈现(在我理解,就是人可以看的呈现),
针对不同的对象,str有不同的操作方法,比如针对于string类型,它会原样返回
对于function类型,str函数会以字符串的形式返回这个函数在内存中的位置
string类型使用str函数时,注意一点,如果是unicode类型的字符串,一定注意当前的默认编码
如下,我在cmd,编码为GBK,python默认编码为ASCII
>>> a=u'好' >>> str(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u597d' in position 0 : ordinal not in range(128) >>>
以上对unicode使用str函数时,这个转换涉及到默认编码内部首先进行这样的转换:unicodeStr.encode(defaultencoding).
如果defaultencoding不是编写代码本身的编码,那就会抛出异常.
所以,要设置defaultencoding,如下
>>> import sys >>> reload(sys) <module 'sys' (built-in)> >>> sys.setdefaultencoding('GBK') #规定默认编码为GBK >>> a=u'啦' >>> str(a) #这里就不会报错了 '\xc0\xb2' >>> str(a)==a True