python编码问题
来源:互联网 发布:东湖高新人工智能峰会 编辑:程序博客网 时间:2024/06/15 02:35
写python的过程中经常出现各种蛋疼的编码问题,于是通过上网查资料,自己做实验,想彻底搞清楚这个问题。
编码和解码的理解
计算机是不认识字符的,计算机只认识二进制的01串,那么字符要存储在计算机中,首先要做的就是把字符用二进制的01串来表示,这就是所谓的编码(encode)
;当我们要阅读存储在计算机中的字符时,计算机就需要把二进制的01串转换成我们可以读的字符,这就是解码(decode)
;所以,我们遇到encode error
, 一般是计算机需要把某个字符进行存储时,使用的编码找不到该字符对应的01串,而我们遇到decode error
时,一般是计算机读取以01串存储的数据,准备转化成我们可识别的字符时,使用的编码识别不了01串。不论是从字符转化成二进制的01串进行存储,还是从二进制的01串转化成我们可读的字符,都需要一个对应的转化表,也就是哪个字符对应哪个01串,关于这样的对应关系有很多种(比如utf-8, gbk等等),就称为编码方式(简称编码,名词)。显然,每种编码方式可以编码的字符都是有限的,那么一种编码方式可以编码的字符集就称作字符集吧。
如果我们用一种编码方式 A 进行encode,用另一种编码方式B进行decode,以“ 我 ” 这个汉字为例,那么就会出现三种情况:一,A和B所使用的字符集中都可以找到“ 我 ” 这个字符,而且A和B表示“ 我 ” 这个字的01串也一样,所以“ 我 ” 这个字的编码和解码就不会存在问题;二,A和B所使用的字符集中都可以找到“ 我 ” 这个字符,但是A和B表示“ 我 ” 这个字符的01串不一致,这时候A按照自己的编码方式将” 我 “ 存储到计算机中,B按照自己的编码方式解读A对“ 我 ” 这个字表示的01串时,就会出现两种情况,一是可以解释,但是显然解释是错误的,可能会对应到另外的字符,这就称之为乱码,我们会看到一堆无意义的字符,另一种是直接不能解释,这时候程序会直接报错,python中就是decode error
; 第三种是B所使用的编码集种直接无法找到“ 我 ”, 其表现和第二种一样。
python中的编码
一、python文件的编码
python文件是由python语言解释器进行解释执行的,默认情况下python解释器对python文件用ascii编码方式进行解码,因此如果python文件中包含中文字符,就会报错,如下面test.py的代码
# main 程序def main(): print('hello, world!')main()
执行python test.py
会得到
File "test.py", line 1 SyntaxError: Non-ASCII character '\xe7' in file test.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
我们可以看到Non-ASCII character '\xe5' in file
,也就是说没有声明编码的情况下,python解释器按照ascii解码的时候不认识’\xe5’,现在在这个文件的头部加入编码声明,那么声明为什么编码呢?python解释器读的是这个文件,因此这个文件是按照什么编码存储的就按照什么编码声明,我的编辑器是utf-8编码的,因此我声明为utf-8, 代码如下
# coding: utf-8# main 程序def main(): print('hello, world')main()
这次再执行这个文件,就正常输出了 “hello, world”, 刚才这个编码问题就是我们的编辑器保存代码使用的编码和python解释器解释代码使用的编码不一致导致的,因此我们通过 # coding: utf-8
告诉python解释器应该使用的编码,这个问题就解决了。
二、python中的字符串和unicode
由于我使用的是python2.7, 因此,仅针对python2.7讨论这个问题。python中有str和unicode两种表示字符串的方式,他们均继承自basestring, 但是却是完全不同的两个东东。str可以说并不是真正的字符串,而是已经经过编码的二进制01串,而unicode确实真正的字符串。
# coding: utf-8# main 程序def main(): u=u'大家好' s='大家好' print(len(u)) print(len(s))main()
这段代码的输出是3和9,3我们很好理解,本来就是3个汉字;为什么s的长度是9呢?就是因为s是’大家好’这三个汉字已经编码得到的长度为9字节的01串。这三个汉字已经编码了,那么使用什么编码方式呢?就是编辑器所使用的编码方式,在我这儿也就是utf-8, 我们再做一个实验,对这个问题有更加深刻的理解。
# coding: utf-8# main 程序def main(): u=u'大家好' print(u)main()
我执行 python test.py
,正常输出 “ 大家好 “, 然后我想让这个输出保存到文件中,因此我执行 python test.py > out.txt
, 于是问题出现了,输出下面的错误
Traceback (most recent call last):File "test.py", line 8, in <module>main()File "test.py", line 6, in mainprint(u)UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
为什么我直接输出到终端的时候一切正常,当我想重定向到文件的时候出问题了呢?当我直接输出至终端的时候,按照终端所使用的编码来编码‘大家好’这3个字符,而我的终端所使用的编码是utf-8,和我的编辑器所使用的编码一致,所以不存在问题。但是当我把这个输出要重定向至文件的时候,就出问题了,因为文件本身并不规定编码方式,我也没有对这个字符串进行显式编码,因此python将采用默认的编码方式,而python2.7的默认编码是ascii
,因此会出现UnicodeEncodeError
,搞清楚问题以后,也就有办法解决问题了,一种是我们对这个unicode字符串进行显式编码, 如下所示
# coding: utf-8# main 程序def main(): u=u'大家好' print(u.encode('utf-8'))main()
另一种是改变python的默认编码为我们这个字符串的编码, 如下所示
# coding: utf-8import sysreload(sys)sys.setdefaultencoding('utf-8')# main 程序def main(): u=u'大家好' print(u)main()
一般推荐第一种方式,尽量避免第二种方式,因为第二种方式只有当我们需要处理的编码方式只有一种时有效,如果我们使用多种编码方式,那么仍然会存在问题。我们再看一段代码
# coding: utf-8# main 程序def main(): s='大家好' print(s)main()
对这段代码执行python test.py
直接输出在终端和python test.py > out.txt
都可以得到预期效果,这又是为什么呢?这段代码和之前代码的区别是’大家好’这个字符串是str而不是unicode类型。我们知道str类型是已经编码的01串,因此在输出至终端或文件时不需要再进行编码,所以不会出现之前遇到的问题。
三、思考
这样看,貌似使用str类型更方便一些,省去了我们进行显式的编码了,实则恰恰相反,因为这种隐式的编码方式很不利于代码维护,虽然代码暂时很侥幸,很容易的运行通过了,但是日后我们很难搞清楚这个str里面究竟是什么编码,而且我们也看到通过len拿到的字符串长度也存在问题。而使用第一种unicode的方式,虽然我们写代码时需要多费些功夫,在输出时需要显式进行编码,但是这样也明确了这个字符串所采用的编码,同时拿到的字符串长度也是准确的。
- python编码问题
- python编码问题
- python编码问题
- Python编码问题
- python编码问题
- python 编码问题
- python的编码问题
- Python编码问题总结
- python 中文编码 问题
- Python 中文编码问题
- python编码问题总结
- Python 中文 编码问题
- python默认编码问题
- Python 编码问题整理
- python字符串编码问题
- python pyscripter编码问题
- python中文编码问题
- python 中文编码问题
- 关于java关键字finally的浅入的个人理解
- 第七届蓝桥杯决赛JavaB组第二题_反幻方
- hdu 2084 数塔
- 无向图的割点、桥与双连通分量
- Android开发之DrawerLayout与ToolBar之间不得不说的秘密
- python编码问题
- 极光推送
- Java反射机制==>运行时使用反射分析对象
- JavaScript单线程异步的背后——事件循环机制
- Implement regular expression matching with support for '.' and '*'.
- activity的启动模式有哪些?是什么含义?(一)
- 【暴力模拟】二阶魔方旋转
- 利用RadioGroup嵌套RadioButton实现Android主页面底部导航栏动态设置图片大小
- C++:模板