彻底搞懂py2.x/py3.x中编码和解码问题
admin
2023-07-17 09:03:08
0次

一 结论

1.  字符在内存中都是以unicode类型存在。

2.  当数据要保存到磁盘或者网络传输时,会转为utf-8等编码再保存或传输。

3.  在python文件第一行指定的编码方式用于向python解释器指出解码方式。

4.  Python中字符的存储类型有bytes和unicode,在py2.x中被称为str和unicode, 在py3.x中被称为bytes和str.

5.  Py2.x和py3.x中字符的类型都为str, 因此在py2.x中是bytes类型,在py3.x中是unicode类型。

6.  py2.x中文件默认解码方式(即python文件第一行不指定时)为ASCII, py3.x中为UTF-8. 使用sys.getdefaultencoding()获得。

7.  编码、解码过程。

彻底搞懂py2.x/py3.x中编码和解码问题

彻底搞懂py2.x/py3.x中编码和解码问题

8.  IDE在程序运行前先按文档属性设定的编码方式把数据保存到磁盘,然后python解释器按文件第一行的解码方式把磁盘中存储的二进制序列读取并解码为unicode加载到内存中。


彻底搞懂py2.x/py3.x中编码和解码问题

二 概念

编码:把人类发明的文字及符号转化为计算机能够识别的二进制序列的过程。

解码:把计算机内部存储的二进制序列转化为人类能够认识的文字及符号的过程。

ASCII: 占一个字节,保留最高位,其余7位组成了128个字符的字符集。

unicode: unicode编码了世界上所有的文字。

utf-8: 对unicode进行了压缩和优化。ASCII码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存。

GBK: 汉字的国标码,用2个字节保存。

 

三 py2.x

1.  验证Py2.x中的字符类型。

Py2.x:
#coding:utf-8
s = '中国hello'
print s
print type(s)
print len(s)
print repr(s)
执行结果:
中国hello

11
'\xe4\xb8\xad\xe5\x9b\xbdhello'

可见是str类型,即bytes类型。len()是占用的字节数。

Py2.x:
#coding:utf-8
s = u'中国hello'
print s
print type(s)
print len(s)
print repr(s)
执行结果:
中国hello

7
u'\u4e2d\u56fdhello'

指定了使用unicode类型。 u4e2d是unicode字符集中字符“中”的代码。len()是字符的个数。

2.  bytes和unicode的转换。

#coding:utf-8
s = '中国'
print type(s)
print len(s)
 
s2 = s.decode('utf-8')
type(s2)
print len(s2)
执行结果:

6

2

3.  不同编码类型的字符串拼接。

Py2.x:
#coding:utf-8
print 'cisco'+u'google'
执行结果:
ciscogoogle
之所以英文字符可以把两种类型的进行拼接,是因为在python2.x中,只要数据全部是 ASCII 的话,python解释器自动把 byte 转换为 unicode 。但是一旦一个非 ASCII 字符偷偷进入你的程序,那么默认的解码将会失效,从而造成 UnicodeDecodeError 的错误。python2.x编码让程序在处理 ASCII 的时候更加简单。你付出的代价就是在处理非 ASCII 的时候将会失败。
Py2.x:
#coding:utf-8
s = 'hello'+'china'
print s
print type(s)
print repr(s)
执行结果:
hellochina

'hellochina'
查看不同编码类型拼接后的存储类型:
Py2.x:
#coding:utf-8
s = 'hello'+u'china'
print s
print type(s)
print repr(s)
执行结果:
hellochina

u'hellochina'
可见Py2.x进行了自动转换。
Py2.x:
#coding:utf-8
print '中国'+'美国'
执行结果:
中国美国
Py2.x:
#coding:utf-8
print '中国'+u'美国'
执行结果:
Traceback (most recent call last):
  File "E:\python\study\test\index.py", line 14, in 
    print '中国'+u'美国'
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

Py3.x中即使都是ASCII范围内,也不能进行拼接:

#coding:utf-8
s1 = 'cisco'
print(type(s1))
s2 = b'google'
print(type(s2))
print(s1+s2)
执行结果:


Traceback (most recent call last):
  File "E:\python\study\test\index.py", line 6, in 
    print(s1+s2)
TypeError: can only concatenate str (not "bytes") to str

四 py3.x

1. 验证Py3.x中的字符类型。

#coding:utf-8
import json
s1 = '中国'
print(type(s1))
print(len(s1))
print(json.dumps(s1))
print(s1)
 
s2 = s1.encode('utf-8')
print(type(s2))
print(len(s2))
print(s2)
执行结果:

2
"\u4e2d\u56fd"
中国

6
b'\xe4\xb8\xad\xe5\x9b\xbd'
#coding:utf-8
s = u'中'
print(s)
print(type(s))
print(len(s))
print(repr(s))
print(ord(s))
print(bin(ord(s)))
 
中

1
'中'
20013
0b100111000101101

2.  bytes和unicode的转换。除了encode和decode的转换方法,还可以:

#coding:utf-8
s1 = '中国'
print(type(s1))
 
s2 = bytes(s1,encoding='utf-8')
print(type(s2))
 
s3 = str(s2,encoding='utf-8')
print(type(s3))
执行结果:


五 常见错误

1.  py2.x中默认的解码方式是ASCII, py3.x中默认的是utf-8, 当在py2.x中指定解码方式为utf-8时,py2.x和py3.x应该是没有区别,可为何在py2.x中默认的字符类型是bytes, 而在py3.x中确是unicode, 都是utf-8,不应该都是bytes吗?或者既然都加载在内存了,不该都是unicode吗?

答:python解释器从磁盘读取文件,以unicode编码方式把整个代码加载到内存中,然后逐条执行,当识别到字符串时,py2.x默认的str类型是bytes, 而py3.x默认的str类型是unicode, 但当有明确指定字符类型时,按指定的编码,如py2.x中的u'china', py3.x中的b'google'.

2.  Py2.x中不指定utf-8编码方式时,print汉字会报错:

Py2.x:
s = '中国'
print s
结果:
File "E:\python\study\test\index.py", line 3
SyntaxError: Non-ASCII character '\xe4' in file E:\python\study\test\index.py on line 3, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

这是因为py2.x中默认的解码方式为ASCII, 而文件保存的编码方式为UTF-8, 两者不匹配,因此报错。

3. Py2.x中字符串s本来应该是字节类型,但为何print时却显示为明文了呢?

Py2.x中:
>>> s = '中国'
>>> s
'\xd6\xd0\xb9\xfa'
>>> print s
中国
>>>print '\xd6\xd0\xb9\xfa'
中国

这是因为print在执行时调用了str函数,str函数执行了bytes到unicode的操作。但py3.x中不存在这种现象:

#coding:utf-8
import json
s1 = '中国'
print(type(s1))
print(len(s1))
print(json.dumps(s1))
print(s1)
 
s2 = s1.encode('utf-8')
print(type(s2))
print(len(s2))
print(s2)
执行结果:

2
"\u4e2d\u56fd"
中国

6
b'\xe4\xb8\xad\xe5\x9b\xbd'
控制台中:
>>> s = '中国'
>>> print(type(s))

>>> s
'中国'
>>> print(s)
中国
>>> s1 = bytes(s,encoding='gbk')
>>> s1
b'\xd6\xd0\xb9\xfa'
>>> print(s1)
b'\xd6\xd0\xb9\xfa'
>>>

4.  以utf-8保存文件,在windows中执行,输出不同:

#coding:utf-8
s = '中国'
print(s)
 
D:\Python37-32>python d:\index.py
中国
D:\Python27>python d:\index.py
涓浗

因为py3.x中字符串被识别为unicode, 传给cmd.exe时被编码为GBK,再以GBK解码输出。但py2.x中字符串被识别为bytes, utf-8编码的两个汉字有6个字节,传给cmd.exe时按GBK解码,识别成为了3个乱码,再以GBK解码输出。

5.  Py3.x使用open的r方法打开utf-8编码的文件时会报错:

#coding:utf-8
 
f = open('index.py','r')
print(f.read())
执行结果:
Traceback (most recent call last):
  File "E:\python\study\test\test.py", line 5, in 
    print(f.read())
UnicodeDecodeError: 'gbk' codec can't decode byte 0xad in position 2: illegal multibyte sequence
使用rb时输出:
b'\xe4\xb8\xad\xe5\x9b\xbd'

py2.x中不会报错。open()方法打开文件时,read()读取的是str(py2.x中即是bytes),读取后需要使用正确的编码格式进行decode().

Py2.x:
f = open('index.py','r')
s = f.read()
print type(s)
print len(s)
print s
执行结果:

6
中国
可见,此处使用utf-8进行解码,如果指定为GBK呢?
#coding:gbk
f = open('index.py','r')
s = f.read()
print s
输出是涓浗,改为ASCII后同样报错。

可查看py3.x使用的是GBK进行解码:

Py3.x:
>>> f = open('index.py','r')
>>> f
<_io.TextIOWrapper name='index.py' mode='r' encoding='cp936'>
但py2.x没有显示编码方式:
>>> f = open(r'e:\python\study\test\index.py','r')
>>> s = f.read()
>>> f

可使用open('index.py','r',encoding='utf-8')指定编码方式。

六 参考资料

https://www.cnblogs.com/OldJack/p/6658779.html

http://www.cnblogs.com/yuanchenqi/articles/5938733.html

https://www.cnblogs.com/shine-lee/p/4504559.html

https://blog.csdn.net/nyyjs/article/details/56667626

https://blog.csdn.net/nyyjs/article/details/56670080

https://www.jianshu.com/p/19c74e76ee0a

https://www.jb51.net/article/59599.htm


相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...