编码存在于所有文件,比较常见的ASCII、utf8、gbk等。最常用的还是utf8编码。
在编码领域,也会涉及到代码文件,那么也会涉及编码问题,今天就这一问题进行介绍。
编码就是特定字符的集合,是用于显示特点的字符。比如ASCII只能显示256个字符,utf8则可以表示各种符号多种语言的文字,具有更好的包容性。
一般读取文件内容,我们这么写代码就可以了
- with open("./.env", "r",encoding="utf-8") as f:
- print(f.read())
如上代码,是直接读取环境变量文件,并且设置了编码为utf8,这里如果编码不匹配,就会报错:
UnicodeDecodeError: 'gbk' codec can't decode byte 0x95 in position 8: illegal multibyte sequence
因为读取文件内容的时候,有些中文在不同编码格式下编码信息是不一样的,就会导致报错。
由于一般用的都是utf8编码,那我们平时都用utf8编码,这种出错的情况也会很少。
但是随着Python开发接触的越来越多,你一定会用到很多其他的包,这个时候可能就会出意外了。比如某个包提供一个读取配置文件的方法,你感觉应该没问题,结果执行的时候就报错了,然后翻到包里的代码去看,结果,我的天,它咋不设置编码格式!!!
- with open(str(template_file), "r") as f:
- template = f.read()
一开始我就直接把人家包的代码给改了,加了encoding参数,问题暂时是解决了,但是会后患无穷,包不得更新,一个更新又出问题了,你如果都忘了这事,那真是神不知鬼不觉的。
经过一系列了解,原来这个问题主要出在Windows系统。自从Python3开始,Python的默认编码就是utf8了,这个在Linux、Mac系统下都没问题的。唯独在Windows下有问题,简单说在Windows下Python获取当前编码,还和操作系统编码、区域啥的有关系了
读取文件其实是一个解码的过程,根据提示通过gbk无法解码某个字符,说明当前读取文件用的是gbk编码,但是gbk解码出错,说明读取的文件编码不是gbk,看了下文件编码确实不是gbk,而是utf8。为啥会这样,一会我们说。我们先看咋解决
结合如上分析,一个办法就是我们把文件编码也改为gbk,应该就可以了呗。改了果然可以。
就当我以为要大功告成的时候,突然想起来,Linux一直没这种编码问题的,于是决定用相同代码和相同的文件(修改编码为gbk)在Linux环境测试。
哇咔咔,果断报错。UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 0: invalid start byte
通过上面的分析经验,我们知道Linux默认是用的utf8解码,但是我们的文件却改为了gbk编码,那不报错才怪呢
看来,我这个改法是不行的,不能Windows改好了,结果Linux废了。
还得找路子
这里顺便说下Windows下为啥文件编码默认就是utf8,但是默认解码却是gbk。
文件是我们新建的,和Python本身是没关系的,而文件新建其实我们一般在开发环境下操作,比如我用的就是VSCode,这些开发工具其实默认编码已经设置为了utf8,这也就是为啥文件编码默认是utf8的原因。
而解码是要Python代码来实现,而默认解码同样是Python底层控制的,开发环境在python底层之上,是无法反向干预的。而默认解码在Windows下和操作系统编码、区域(或根据操作系统语言匹配一个编码,gbk就是我们国家的编码)相关的。
问题没解决,只能各种问AI、问度娘了
1)设置PYTHONIOENCODING环境变量————————————没卵用
2)locale.setlocale(locale.LC_ALL, ".UTF-8")——————————没卵用
3)_locale._getdefaultlocale = (lambda *args: ['en_US', 'utf8'])——没卵用
- default_encoding = locale.getpreferredencoding()
- print("当前环境的默认编码是:", default_encoding)
如上代码可以查看当前环境的默认编码,但是经过如上设置,这个默认编码还是cp936,其实就是gbk,cp936是Windows操作系统内部编码叫法,可见很大概率和操作系统有关系
4)sys.setdefaultencoding('utf-8')——————————————没卵用,还报错
这玩意其实是Python2中才有的,Python3默认编码就是utf8,这玩意取消了,所以在搜索信息的时候还要明确是Python3
5)指定sys.flags.utf8_mode————————————————没卵用,还报错
sys.flags.utf8_mode是只读属性无法设置
好奇会害死猫
好奇也会让我都不想去吃饭,不想出去遛弯,只为找到真理
终于找到两个个靠谱的
1)设置环境变量PYTHONUTF8=1
测试no problem。
2)重写open,从而给open加了encoding参数
- original_open = __builtins__.open
- def uopen(*args, **kwargs):
- if "b" not in (args[1] if len(args) >= 2 else kwargs.get("mode", "")):
- kwargs.setdefault("encoding", "UTF-8")
- return original_open(*args, **kwargs)
- __builtins__.open = uopen 如上代码干啥用的,使用了python的哪些技术点
测试同样ok
附上参考链接:1. 命令行和环境 — Python 3.12.3 文档https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUTF8
3)命令行运行增加-X utf8参数
运行py命令:python xx.py,注意是在python和xx.py之间增加
完整命令:python -X utf8 xx.py
测试可用,不过仅限于命令窗口,PyCharm中可以设置运行的时候增加这个脚本,不过我用的CSCode,参考链接:Python open 默认编码修改_python open utf8-CSDN博客https://blog.csdn.net/linuxweiyh/article/details/124538216
如上5.终极解决,有几个方案可选,但是从通用性考虑,还是通过改环境变量的方式最省事。
其他办法要不不通用,要不需要修改的代码比较多,比如重写open,涉及问题的代码文件都得加这个代码。
改环境变量就没这个问题,反正Linux默认就是utf8,Windows和Linux、Mac统一了也没啥问题。
通过一个小小的编码,引出一个Windows操作系统下Python编码的问题,网上相关资料很多,但是真正解决问题的资料却偏少,是不是多数Python开发用Linux、Mac操作系统。
不管如何,总算解决问题了。
Python入门第01篇(Python安装与开发工具)-CSDN博客
Python入门第02篇(pip、字符串、方法、json、io操作)_python json pip-CSDN博客
Python入门第03篇(异常处理、dotenv)_load_dotenv()-CSDN博客
Python入门第04篇(sqlite数据库相关)_cmd中使用sqlite-CSDN博客
Python入门第06篇(FastApi、uvicorn)_fastapi uvicorn-CSDN博客
Python入门第09篇(conda虚拟环境)-CSDN博客