open() 函数默认使用哪种编码?

61

我尝试使用以下代码来读取一个使用UTF-8编码的JSON文件:

input = open("json/world_bank.json")
i=0
for l in input:
    i+=1
print(i)

但是我遇到了一个 UnicodeDecodeError。不过,当我尝试显式指定编码时,它开始工作了:

input = open("json/world_bank.json",encoding="utf8")

我以为open函数会使用"utf8"作为默认编码方式?为什么需要指定呢?


2
在你的系统上,sys.getfilesystemencoding() 返回什么? - marcelm
这里是'mbcs' @marcelm - Subbi reddy dwarampudi
啊,嗯,这并没有告诉我太多信息;你能同时检查一下 open("json/world_bank.json").encoding 吗? - marcelm
2个回答

84
Python 3 的默认 UTF-8 编码仅适用于 bytesstr 类型之间的转换。而 open() 则会根据环境选择一个合适的默认编码

encoding 是用于解码或编码文件的编码名称。这只应在文本模式下使用。默认编码取决于平台(即 locale.getpreferredencoding() 返回的值),但 Python 支持的任何文本编码都可以使用。请参阅 codecs 模块以获取支持的编码列表。

例如,具有西欧/北美区域设置的 Windows 计算机通常会使用 8 位 Windows-1252 字符集(Python 将此编码称为 'cp1252')。

19
幸运的是,最近有一些尝试来结束这种疯狂......也许有一天。 - Jeyekomon
3
我的机器上安装了Python 3.9,仍在使用Windows 1252编码。@Jeyekomon提供的PEP 597现在指出Python 3.10已经发布。 - Stefan Berger
1
@StefanBerger 各位,读一下PEP吧。它只是关于在未设置encoding参数时发出警告而已。他们提到他们意识到了编码问题,但这个更改太大了。这个PEP应该能够在将来实际的默认utf-8打开编码PEP草案起草时简化流程。 - Jeyekomon
3
这是一个非常糟糕的决定的典型例子,它是很久以前做出的。如果不需要跨平台的东西默认上就不跨平台,为什么还要伪装成跨平台呢? - zumalifeguard
6
疯狂终将在Python 3.15中结束。PEP 686:使UTF-8模式成为默认模式已被接受。 - Jan Derk
1
Windows的消亡终将结束这种疯狂。sys.getfilesystemencoding()#'utf-8'``locale.getpreferredencoding()#'cp1252' - NeilG

6

按照这里的建议,问题也可以通过设置环境变量PYTHONUTF8=1来解决。这会导致open默认使用UTF-8编码,而不是平台的默认编码。


这被称为“UTF-8模式”,它强制Python忽略本地环境语言环境。请参见https://docs.python.org/3/library/os.html#utf8-mode。与往常一样,通过设置正确的语言环境来修复根本原因会更好,这应该会导致更健康的系统。 - Alastair McCormack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接