024Python2和Python3字符编码的区别

时间:2019-11-03
本文章向大家介绍024Python2和Python3字符编码的区别,主要包括024Python2和Python3字符编码的区别使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Python2和Python3字符编码的区别


一、字符编码应用之Python

1.1 执行Python程序的三个阶段

python test.py(我在强调一遍,执行test.py的第一步,一定是将文件内容从硬盘读儒到内存中)

test.py文件内容以gbk格式保存的,内容为:

  • 阶段一:启动Python解释器

  • 阶段二:Python解释器此时就是一个文本编辑器,负责打开文件test.py,即从硬盘中读取test.pyde 内容到内存中去

此时Python解释器会读取test.py的第一行内容,#coding:utf-8或者#-*-coding:utf-8-*-,以此决定以什么编码格式将代码读入内存,这一行就是设定Python解释器这个软件使用的编码格式。

可以sys.getdefaultencoding()查看,如果不在Python文件制定头信息,#-*-coding:utf-8-*-,那就使用Python默认的编码格式。

import sys
print(sys.getdefaultencoding())
###输出结果:
utf-8

Python2中默认使用的ascii,Python3中默认使用utf-8.

改正:在test.py指定文件头,字符编码一定要为gbk。即更正为

#coding:gbk
你好啊
  • 阶段三:读取已经加载到内存的代码(Unicode编码格式),然后执行,执行过程中可能会开辟新的内存空间,比如name="reed"

内存的编码使用Unicode,不代表内存中全都是Unicode,因为在程序执行之前,内存中确实都是Unicode,比如从文件中读取了一行name="reed",其中的name、等号、引号的地位都一样,都是普通字符而已,都是以Unicode的格式存放于内存中。

但是程序在执行过程中,会申请内存(与程序代码所存在的内存是两个空间)用来存放Python的数据类型的值,而Python的字符串类型有涉及到了字符的概念。

比如name="reed"会被Python解释器识别为字符串,会申请内存空间来存放字符串类型的值,至于该字符串类型的值被识别成何种编码存放,这就与python解释器有关了,而python2与Python3的字符串类型又有所不同。

二、Python2与Python3字符串类型的区别

2.1 Python2

在Python2中两种字符串类型Str和Unicode

2.1.1 Str类型

在Python解释器执行到长生字符串的代码时(例如x=上),会申请新的内存地址,然后将‘上’编码成文件开头指定的编码格式。
因为直接print()会自动转换编码,我们使用encode()方法查看'还是那"上"的字符编码

# 三、Python2中代码

# 四、coding:gbk

x = '上'
y = '下'
print([x, y])  # ['\xc9\xcf', '\xcf\xc2']
# 五、\x代表16进制,此处是c9cf总共4位16进制数,一个16进制四4个比特位,4个16进制数则是16个比特位,即2个Bytes,这就证明了按照gbk编码中文用2Bytes

print(type(x),type(y))  # (<type 'str'>, <type 'str'>)

理解字符编码的关键!!!

内存中的数据通常用16进制表示,2位16进制数据代表一个字节,如\xc9,代表两位16进制,一个字节。

gbk存中文需要2个bytes,而存英文需要1个bytes,它是如何做到的???!!!

gbk会在每个bytes,即8位bit第一位作为标志位,标志位为1代表是中文字符,如果标志位为0则表示为英文字符。

x='你a好'

转成gbk格式二进制位:

8bit+8bit+8bit+8bit+8bit=(1+7bit)+(1+7bit)+(0+7bit)+(1+7bit)+(1+7bit)

这样计算机按照从左向右的顺序读:

  1. 连续读到前两个括号内的首位标志位均为1,则构成一个中文字符:你

  2. 读到第三个括号的首位标志位0,则8bit代表一个英文字符:a

  3. 连续读到后两个括号内的首位标志位均为1,则构成一个中文字符:好

也就是说,每个Bytes留给我们用来存真正值的有效位数只有7位,而在Unicode表中存放的只有这有效的7位,至于首位的标志位与集体的编码有关,即在Unicode中表示gbk的方式为:

(7bit)+(7bit)+(7bit)+(7bit)+(7bit)

按照上图翻译的结果,我们可以去Unicode关于汉字的对应关系中去查:链接:

"Unicode汉字对应表"

可以看到“上”对应的gbk(G0代表的是gbk)编码就为494F,即我们得出的结果,而上对应的Unicode编码为4E0A,我们可以将gbk-->decode-->Unicode.

##六、Python2中代码
##七、coding:gbk
x='上'.decode('gbk')
y='下'.decode('gbk')
print([x,y]) # [u'\u4e0a', u'\u4e0b']

2.2 Unicode类型

当Python解释器执行到产生字符串的代码时(例如s=u'林'),会申请新的内存地址,然后将‘林’以Unicode的格式存放到新的内存 空间中,所以s只能是encode,不能是decode。

# 八、Python2中代码

# 九、coding:gbk

x = u'上'  # 等同于 x='上'.decode('gbk')
y = u'下'  # 等同于 y='下'.decode('gbk')
print([x, y])  # [u'\u4e0a', u'\u4e0b']
print(type(x),type(y))  # (<type 'Unicode'>, <type 'Unicode'>)

对于print需要特别说明的是:当程序执行时,比如x='上'#gbk下,字符串存放为\xc9\xcf.

print(x)这一步是将x指向的那块新的内存空间(非代码所在的内存空间)中的内存,打印到终端,按理说应该是存的什么就打印什么,但打印\xc9\xcf,对一些不熟知Python编码的程序猿,立马就懵逼了,所以龟叔自作主张,在print(x)时,使用终端的编码格式,将内存中的\xc9\xcf转成字符显示,此时就需要终端编码必须gbk,否则无法正常显示原内容:上。

对于Unicode格式的数据来说,无论怎么打印,都不会乱码

Unicode这么好,不会乱码,那么Python2为何还那么变扭,高一个str出来呢?Python诞生之时,Unicode并未像今天这样普及,很明显,好的东西你能看的见,但是龟叔早就看见了,龟叔在Python3将str直接存成了Unicode,我们定义了一个str,无论是否加u前缀,就是一个Unicode。

2.3Python3

Python3中的str都是Unicode编码的,所以Python3中的Str类型的数据可以编码成其他字符编码的格式,编码的结果为Bytes类型。

#coding:gbk
x='上'  # 当程序执行时,无需加u,'上'也会被以Unicode形式保存新的内存空间中。
print(f'type(x):{type(x)}')  # <class 'str'>
#x可以直接encode成任意编码格式
print(f'x.encode('gbk'):{x.encode('gbk')}') #b'\xc9\xcf'
print(f'type(x.encode('gbk')):{type(x.encode('gbk'))}') #<class 'bytes'>
##输出结果:
type(x): <class 'str'>
x.encode('gbk'): b'\xc9\xcf'
type(x.encode('gbk')): <class 'bytes'>

很重要的一点是:看到Python3中x.encode('gbk')的结果是\xc9\xcf正是Python2中的str类型的值,而Python3是bytes类型,在 Python2中则是Str类型。

总而言之

代码详情 Python2执行情况 Python3执行情况
# coding:gbk print("中")终端:utf-8 乱码 不乱码
# coding:utf-8 print("中")终端:utf-8 不乱码 不乱码
# coding:gbk print(u'中')终端:utf8 不乱码 不乱码
# coding:utf8 print(u'中')终端:utf8 不乱码 不乱码

在Python2中如果指定了字符编码,那么内存存取就会按照 指定的字符编码去存入内存。解释或去执行时就要按照指定的字符编码去解释,否则就会乱码,否则可以在定义变量前面加上u,这样变量就会以Unicode编码存入内存中。

如:

# coding gbk

name="妈妈"

但是Python3中就不会有这样的问题,因为无论你指定了什么字符编码,在内存存取时都会使用Unicode编码去入内存,Unicode编码可以和任意的字符编码相互转换,并在读取时按照所需的编码去读取,这样就很好解决了编码的问题。

原文地址:https://www.cnblogs.com/FirstReed/p/11785838.html