在之前的文章中,我们介绍过编码格式的发展史:[文章传送门-todo]。今天我们通过几个例子,来彻底搞清楚python3中的编码格式原理,这样你之后写python脚本时碰到编码问题,才能有章可循。

我们先搞清楚几个概念:

  • 系统默认编码:指python解释器默认的编码格式,在python文件头部没有声明其他编码格式时,python3默认的编码格式是utf-8。
  • 本地默认编码:操作系统默认的编码,常见的Windows的默认编码是gbk,Linux的默认编码是UTF-8。
  • python文件头部声明编码格式:修改的是文件的默认编码格式,只是会影响python解释器读取python文件时的编码格式,并不会改变系统默认编码和本地默认编码。

通过python自带的库,可以查看系统默认编码和本地默认编码

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
>>> import locale
>>> locale.getdefaultlocale()
('zh_CN', 'cp936')
>>>

注意,因为我在windows系统的电脑上 进行测试,所以系统默认编码返回“cp936”, 这是代码页(是字符编码集的别名),而936对应的就是gbk。如果你在linux或者mac上执行上面的代码,应该会返回utf-8编码。

其实总结来看,容易出现乱码的场景,基本都与读写程序有关,比如:读取/写入某个文件,或者从网络流中读取数据等,因为这个过程中涉及到了编码解码的过程,只要编码和解码的编码格式对应不上,就容易出现乱码。下面我们举两个具体的例子,来验证下python的编码原理,帮助你理解这个过程。注意:下面的例子都是在pycharm中写的。

01默认的编码格式

我们新建一个encode_demo.py的文件,其文件默认的编码格式是UTF-8(可以从pycharm右下角看到编码格式),代码如下:

"""
@author: asus
@time: 2019/11/21
@function: 验证编码格式
"""
import sys, locale def write_str_default_encode():
s = "我是一个str"
print(s)
print(type(s))
print(sys.getdefaultencoding())
print(locale.getdefaultlocale()) with open("utf_file", "w", encoding="utf-8") as f:
f.write(s)
with open("gbk_file", "w", encoding="gbk") as f:
f.write(s)
with open("jis_file", "w", encoding="shift-jis") as f:
f.write(s) if __name__ == '__main__':
write_str_default_encode()

我们先来猜测下结果,因为我们没有声明编码格式,所以python解释器默认用UTF-8去解码文件,因为文件默认编码格式就是UTF-8,所以字符串s可以正常打印。同时以UTF-8编码格式写文件不会出现乱码,而以gbk和shift-jis(日文编码)写文件会出现乱码(这里说明一点,我是用pycharm直接打开生成的文件查看的,编辑器默认编码是UTF-8,如果在windows上用记事本打开则其默认编码跟随系统是GBK,gbk_file和utf_file均不会出现乱码,只有jis_file是乱码),我们运行看下结果:

# 运行结果
我是一个str
<class 'str'>
utf-8
('zh_CN', 'cp936') # 写文件utf_file、gbk_file、jis_file文件内容分别是:
我是一个str
����һ��str
�䐥�꘢str

和我们猜测的结果一致,下面我们做个改变,在文件头部声明个编码格式,再来看看效果。

02 python头文件声明编码格式

因为上面文件encode_demo.py的格式是UTF-8,那么我们就将其变为gbk编码。同样的我们先来推测下结果,在pycharm中,在python文件头部声明编码为gbk后(头部加上 # coding=gbk ),文件的编码格式变成gbk,同时python解释器会用gbk去解码encode_demo.py文件,所以运行结果应该和用UTF-8编码时一样。运行结果如下:

# 运行结果
我是一个str
<class 'str'>
utf-8
('zh_CN', 'cp936') # 写文件utf_file、gbk_file、jis_file文件内容分别是:
我是一个str
����һ��str
�䐥�꘢str

结果确实是一样的,证明我们推论是正确的。接下来我们再做个尝试,假如我们将(# coding=gbk)去掉(需要注意,在pycharm中将 # coding=gbk去掉,并不会改变文件的编码格式,也就是说encode_demo.py还是gbk编码),我们再运行一次看结果:

  File "D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py", line 4
SyntaxError: Non-UTF-8 code starting with '\xd1' in file D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py on line 5, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

运行直接报错了,我们加个断点,看看具体的异常信息:

看错误提示是UnicodeDecodeError,python解释器在对encode_demo.py文件解码时,使用默认的UTF-8编码,但是文件本身是gbk编码,所以当碰到有中文没办法识别时,就抛出DecodeError。

03 敲黑板,划重点

python3中的str和bytes

python3的重要特性之一就是对字符串和二进制流做了严格的区分,我们声明的字符串都是str类型,不过Str和bytes是可以相互转换的:

def str_transfor_bytes():
s = '我是一个测试Str'
print(type(s))
# str 转bytes
b = s.encode()
print(b)
print(type(b))
# bytes转str
c = b.decode('utf-8')
print(c)
print(type(c)) if __name__ == '__main__':
str_transfor_bytes()

需要注意一点:在调用encode()和decode()方法时,如果不传参数,则会使用python解释器默认的编码格式UTF-8(如果不在python头文件声明编码格式)。但是如果传参的话,encode和decode使用的编码格式要能对应上。

python3默认编码是UTF-8?还是Unicode?

经常在很多文章里看到,python3的默认编码格式是Unicode,但是我在本文中却一直在说python3的默认编码格式是UTF-8,那么哪种说法是正确的呢?其实两种说法都对,主要得搞清楚Unicode和UTF-8的区别(之前文章有提到):

  • Unicode是一个字符集,说白了就是把各种编码的映射关系全都整合起来,不过它是不可变长的,全部都以两个字节或四个字节来表示,占用的内存空间比较大。
  • UTF-8是Unicode的一种实现方式,主要对 Unicode 码的数据进行转换,方便存储和网络传输 。它是可变长编码,比如对于英文字母,它使用一个字节就可以表示。

在python3内存中使用的字符串全都是Unicode码,当python解释器解析python文件时,默认使用UTF-8编码。

open()方法默认使用本地编码

在上面的例子中,我们往磁盘写入文件时,都指定了编码格式。如果不指定编码格式,那么默认将使用操作系统本地默认的编码格式,比如:Linux默认是UTF-8,windows默认是GBK。其实这也好理解,因为和磁盘交互,肯定要考虑操作系统的编码格式。这有区别于encode()和decode()使用的是python解释器的默认编码格式,千万别搞混淆了。

总结

不知道你看完上面的例子后,是否已经彻底理解了python3的编码原理。不过所有的编码问题,都逃不过“编码”和“解码”两个过程,当你碰到编码问题时,先确定源文件使用的编码,再确定目标文件需要的编码格式,只要能匹配,一般就可以解决编码的问题。

【python测试开发栈】带你彻底搞明白python3编码原理的更多相关文章

  1. 【python测试开发栈】python基础语法大盘点

    周边很多同学在用python,但是偶尔会发现有人对python的基础语法还不是特别了解,所以帮大家梳理了python的基础语法(文中的介绍以python3为例).如果你已然是python大牛,可以跳过 ...

  2. 【python测试开发栈】python内存管理机制(一)—引用计数

    什么是内存 在开始进入正题之前,我们先来回忆下,计算机基础原理的知识,为什么需要内存.我们都知道计算机的CPU相当于人类的大脑,其运算速度非常的快,而我们平时写的数据,比如:文档.代码等都是存储在磁盘 ...

  3. 【python测试开发栈】—python内存管理机制(二)—垃圾回收

    在上一篇文章中(python 内存管理机制-引用计数)中,我们介绍了python内存管理机制中的引用计数,python正是通过它来有效的管理内存.今天来介绍python的垃圾回收,其主要策略是引用计数 ...

  4. 【python测试开发栈】—理解python深拷贝与浅拷贝的区别

    内存的浅拷贝和深拷贝是面试时经常被问到的问题,如果不能理解其本质原理,有可能会答非所问,给面试官留下不好的印象.另外,理解浅拷贝和深拷贝的原理,还可以帮助我们理解Python内存机制.这篇文章将会通过 ...

  5. 【python测试开发栈】—帮你总结Python os模块高频使用的方法

    Python中的os模块是主要和系统操作相关的模块,在平时的工作中会经常用到,花时间整理了os模块的高频使用方法,同时整理出使用时需要注意的点.归纳来讲,os模块的方法可以分为:目录操作.文件操作.路 ...

  6. 【python测试开发栈】帮你总结python random模块高频使用方法

    随机数据在平时写python脚本时会经常被用到,比如随机生成0和1来控制逻辑.或者从列表中随机选择一个元素(其实抽奖程序也类似,就是从公司所有人中随机选择中奖用户)等等.这篇文章,就帮大家整理在pyt ...

  7. 《Python测试开发技术栈—巴哥职场进化记》—前言

    写在前面 今年从4月份开始写一本讲Python测试开发技术栈的书,主要有两个目的,第一是将自己掌握的一些内容分享给大家,第二是希望自己能系统的梳理和学习Python相关的技术栈.当时我本来打算以故事体 ...

  8. 《Python测试开发技术栈—巴哥职场进化记》—初来乍到,请多关照

    上文<巴哥职场进化记-Python测试开发技术栈>开篇讲到巴哥毕业初到深圳,见到了来自五湖四海的室友.一番畅聊之后,抱着对未来职场生活的期待,大家都进入了梦乡.今天我们来看看巴哥第一天上班 ...

  9. 《Python测试开发技术栈—巴哥职场进化记》—软件测试工程师“兵器库”

    上文<Python测试开发技术栈-巴哥职场进化记>-初来乍到,请多关照 我们介绍了巴哥入职后见到了自己的导师华哥,第一次参加团队站会,认识了团队中的开发小哥哥和产品小姐姐以及吃到了公司的加 ...

随机推荐

  1. [POJ2262] Goldbach’s Conjecture

    Goldbach's Conjecture Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 48161   Accepted: ...

  2. Pathon中numpy模块

    目录 numpy模块 切割矩阵 矩阵元素替换 矩阵的合并 通过函数创建矩阵 fromstring/fromfunctions 矩阵的运算 常用矩阵运函数 矩阵的点乘 矩阵的逆 矩阵的其他操作 nump ...

  3. NodeJs编写Cli实现自动初始化新项目目录结构

    应用场景 前端日常开发中,会遇见各种各样的cli,这些工具极大地方便了我们的日常工作,让计算机自己去干繁琐的工作,而我们,就可以节省出大量的时间用于学习.交流.开发. 注释:文章附有源码链接! 使用工 ...

  4. IaaS基础平台

    第一部分:IaaS云计算基础架构平台 服务器:先电 任务一.IaaS云平台搭建 基础环境: 1.使用命令行方式设置主机名,防火墙以及 SELinux 设置如下: (1)设置控制节点主机名 contro ...

  5. 音视频入门-12-手动生成一张PNG图片

    * 音视频入门文章目录 * 预热 上一篇 [PNG文件格式详解]详细介绍了 PNG 文件的格式. PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDA ...

  6. Robot Framework——对时间操作的datetime库常用关键字

    1.对固定日期进行操作,增加或减去单位时间或者时间段 2.对两个时间段进行操作 3.对时间格式转化,获取时间戳 4.从完整时间中取指定年月日等 5.对时间类型进行格式化 6.获取当前时间或者指定时区时 ...

  7. IDEA配置maven+错误记录

    使用maven并不是那么顺利所以把自己遇到的问题也记录一下 下载maven 从官网下载maven官网 配置环境变量 新建一个变量名:MAVEN_HOME 值:maven目录 path:%MAVEN_H ...

  8. Jdk14都要出了,还不能使用 Optional优雅的处理空指针?

    1. 前言 如果你没有处理过空指针,那么你不是一位真正的 Java 程序员. 空指针确实会产生很多问题,我们经常遇到空的引用,然后又想从这个空的引用上去获取其他的值,接着理所当然的碰到了 NullPo ...

  9. Java中 实体类 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念

    PO(persistant object) 持久对象 在 o/r 映射的时候出现的概念,如果没有 o/r 映射,没有这个概念存在了.通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理.可以 ...

  10. JVM参数及调优

    ## 3.2.1 JVM参数及调优 ### 调优基本概念 在调整JVM性能时,通常有三个组件需要考虑:1. 堆大小调整2. 垃圾收集器调整3. JIT编译器 大多数调优选项都与调整堆大小和选择合适的垃 ...