python编码问题,从隐隐作痛到除去病根

 查阅的资料链接

python编码为什么这么蛋疼

python2.7手册str函数

 

 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

 

posted @ 2017-11-11 17:40  toDoYourBest  阅读(763)  评论(0编辑  收藏  举报