Windows 上 Python 默认编码实测:本机默认仍是 cp936
一条被反复转述、但这台机器上不成立的结论
搜 Windows 上 Python 中文乱码,常见说法是默认编码为 GBK(cp936),写文件不指定 encoding 就会踩坑。近两年又看到另一种说法:新版 Python 已经默认用 utf-8 了,不用再操心。两种说法互相矛盾,当场测一次就知道。我在这台 Windows 机器上把下面要用的四个值打印出来,结果与后一种说法对不上。
三组对照:默认、关掉、打开
import sys, locale, os, tempfile
p = os.path.join(tempfile.gettempdir(), "_enc_probe.txt")
f = open(p, "w")
print("utf8_mode:", sys.flags.utf8_mode)
print("open.encoding:", f.encoding)
f.close()
os.remove(p)
print("preferred:", locale.getpreferredencoding())
print("default:", sys.getdefaultencoding())
同一段代码,只改启动时的环境变量,结果分三种:
不设任何变量时,utf8_mode 是 0,open 的默认编码是 cp936,preferred 是 cp936,default 是 utf-8。
设 PYTHONUTF8=0 时,四项跟默认完全一样。因为这台机器本来就没开 UTF-8 模式,再关一次不会有任何变化。
设 PYTHONUTF8=1 时,四项变成 1、utf-8、utf-8、utf-8。
默认这一行才是重点:这台机器没开 UTF-8 模式,open 不写 encoding 拿到的就是 cp936。所以「新版已经默认 utf-8」这个说法不适用于本机;在这三组对照里,也只有显式设成 1 才让 open 的默认编码变过来。这不代表它是唯一途径,别的入口同样可能改写这个默认值,所以别把结论反过来当成「只要看版本号就知道编码」。
别把 default 当成 open 的默认值
四列里只有 default 从头到尾都是 utf-8,一次都没变。它和 open 的默认编码不是同一个量,也不决定 open 用哪个编码;把它当成 open 的默认编码,很容易得出「明明显示 utf-8,怎么文件还是 GBK」这种结论。
除了固定不变的 default,另外三列都跟着启动环境一起变。所以排查时该看的是这三列,而不是那一列从头到尾没动的 default。
于是同一个 open(p, "w") 在不同启动环境下写出的字节可能不同,读写两侧对编码的假设一旦错开,字节就对不上了。这也是「在我这儿好好的、到你那儿就乱码」的一种来源:代码里没有一行跟编码有关,行为却由启动环境决定。
把编码显式写出来
不管默认是什么,读写两侧都把编码写明:
with open("data.txt", "w", encoding="utf-8") as f:
f.write("中文内容")
with open("data.txt", "r", encoding="utf-8") as f:
print(f.read())
这样至少把「用哪个编码」这一维锁定了,不用去猜当前环境是哪一组。要注意显式写 encoding 并不等于把所有平台差异都消掉,换行翻译、路径编码这些仍然各自受环境影响,只是不会再因为默认编码猜错而读写不一致。
别用印象判断当前环境
遇到编码问题,先花十秒把上面四列打印出来,确认当前机器属于哪一组,再决定怎么改。默认编码是会被环境左右的值,靠记忆或搜索结果去猜,很容易在已经变过的环境上南辕北辙。乱码排查最怕拿一个没验证过的前提往下推,前提错了,后面每一步都白费力气。
- 点赞
- 收藏
- 关注作者
评论(0)