带你彻底搞明白python3编码原理

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

  • 系统默认编码:指python解释器默认的编码格式,在python文件头部没有声明其他编码格式时,python3默认的编码格式是utf-8 。
  • 本地默认编码:操作系统默认的编码,常见的windows的默认编码是gbk,linux的默认编码是UTF-8 。
  • python文件头部声明编码格式:修改的是文件的默认编码格式,只是会影响python解释器读取python文件时的编码格式,并不会改变系统默认编码和本地默认编码 。
通过python自带的库,可以查看系统默认编码和本地默认编码
CopyPython 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32Type "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默认的编码格式#
【带你彻底搞明白python3编码原理】我们新建一个encode_demo.py的文件,其文件默认的编码格式是UTF-8(可以从pycharm右下角看到编码格式),代码如下:
Copy""" @author: asus @time: 2019/11/21 @function: 验证编码格式"""import sys, localedef 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是乱码),我们运行看下结果:
Copy# 运行结果我是一个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编码时一样 。运行结果如下:
Copy# 运行结果我是一个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编码),我们再运行一次看结果:
Copy File "D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py", line 4SyntaxError: 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


推荐阅读