在 Windows 中更改 Python 3 中的“区域设置首选编码”

Posted

技术标签:

【中文标题】在 Windows 中更改 Python 3 中的“区域设置首选编码”【英文标题】:Changing the “locale preferred encoding” in Python 3 in Windows 【发布时间】:2015-10-06 19:31:54 【问题描述】:

我正在使用 Python 3(最近从 Python 2 切换)。我的代码通常在 Linux 上运行,但有时(不经常)在 Windows 上运行。根据open() 的Python 3 文档,如果未提供encoding 参数,则文本文件的默认编码来自locale.getpreferredencoding()。对于我的项目,我希望这个默认值是utf-8,无论它在什么操作系统上运行(目前,对于 Linux,它始终是 UTF-8,但对于 Windows 不是)。该项目有很多对open() 的调用,我不想将encoding='utf-8' 添加到所有这些调用中。因此,我想在 Windows 中更改语言环境的首选编码,就像 Python 3 所看到的那样。

我发现了一个以前的问题 “Changing the "locale preferred encoding"”,它有一个公认的答案,所以我认为我很高兴。但不幸的是,该答案中的建议命令及其第一条评论都不适用于 Windows。具体来说,接受的答案和它的第一条评论建议运行chcp 65001set PYTHONIOENCODING=UTF-8,我都试过了。请从我的 cmd 窗口查看以下脚本:

> py -i
Python 3.4.3 ...
>>> f = open('foo.txt', 'w')
>>> f.encoding
'cp1252'
>>> exit()

> chcp 65001
Active code page: 65001

> py -i
Python 3.4.3 ...
>>> f = open('foo.txt', 'w')
>>> f.encoding
'cp1252'
>>> exit()

> set PYTHONIOENCODING=UTF-8

> py -i
Python 3.4.3 ...
>>> f = open('foo.txt', 'w')
>>> f.encoding
'cp1252'
>>> exit()

请注意,即使在两个建议的命令之后,我打开的文件的编码仍然是cp1252,而不是预期的utf-8

【问题讨论】:

也许这只是我的风格,但我更愿意编写一个包装器 open() 函数,您可以在其中指定编码。 不要使用chcp 65001。 Windows 控制台不正确地支持 UTF-8,而且它也没有做你想做的事。 locale.getpreferredencoding 与控制台代码页无关;它基于 Windows 语言环境的 ANSI 编码。例如,如果您调用 Win32 CreateFileA (ANSI) 而不是 CreateFileW (UTF-16),则文件路径字符串将被解码为 ANSI 字符串(例如 Windows-1252)。 Windows 不允许将 UTF-8 用作 ANSI 字符集,C 运行时也不允许将 UTF-8 用于语言环境。 @eryksun 感谢您提供的信息,但它对我来说有太多特定于 Windows 的行话。我很少使用 Windows。我想要的只是一种对 Windows 8 或 Python 3 说的方式:“亲爱的 Windows 8 / Python 3,请注意,这台计算机上的所有文本文件都应该毫无例外地以 UTF-8 编码。请记住这个事实将来打开文本文件时。谢谢。” @walrus,不存在这样的东西。 Windows 上的原生字符串格式是 UTF-16,使用 16 位 wchar_t 字符串。 Windows API 仅支持旧版 ANSI API 的 8 位编码,遗憾的是它不允许 UTF-8。 Python 的首选编码只是调用GetACP 来获取ANSI 代码页。我同情你并希望io.TextIOWrapper 在所有平台上都默认为 UTF-8(你对 Linux 的假设也不总是有效的)。就目前情况而言,您需要一个包装函数,如前所述。 稍微努力一下就可以找到TextIOWrapper 源,并在其中看到_Py_device_encoding 是使用Windows 控制台代码页(GetConsoleCP) 的,但仅适用于stdin、stdout 和stderr .否则它调用getpreferredencoding,它调用_getdefaultlocale,因此调用GetACP 【参考方案1】:

从 python3.5.1 开始,这个 hack 看起来像这样:

import _locale
_locale._getdefaultlocale = (lambda *args: ['en_US', 'utf8'])

此后打开的所有文件都将假定默认编码为utf8

【讨论】:

或者更好的是,utf_8_sig,因为它会处理一些 Windows 编辑器倾向于注入文件的 BOM 字符,即使是像 utf8 这样的中性字节编码。【参考方案2】:

我知道这是一个真正的 hacky 解决方法,但您可以像这样重新定义 locale.getpreferredencoding() 函数:

import locale
def getpreferredencoding(do_setlocale = True):
    return "utf-8"
locale.getpreferredencoding = getpreferredencoding

如果你早点运行它,所有打开的文件(至少在我在 win xp 机器上的测试中)都以 utf-8 格式打开,并且由于这会覆盖模块方法,这将适用于所有平台。

【讨论】:

我在 python 3.5.1 和 windows 7 和 have a look 上测试了我最终得到的结果。 这似乎不起作用,至少在我的 Windows 10 和 pyhton 3.6.8 上 @sandwood 看看上面的 axils 答案,了解在 python 3.5 之后工作的答案 感谢您的帮助。是的@axil 答案适用于 3.6.8 奇怪的是对应于 3.6 的 python 文档,你的答案应该有效。【参考方案3】:

帖子已过时,但问题仍然存在(在 Python 3.7 和 Windows 10 下)。

我对解决方案进行了如下改进,确保不会覆盖语言/国家/地区部分,而只会覆盖编码,并确保仅在 Windows 下完成:

if os.name == "nt":
    import _locale
    _locale._gdl_bak = _locale._getdefaultlocale
    _locale._getdefaultlocale = (lambda *args: (_locale._gdl_bak()[0], 'utf8'))

希望这会有所帮助...

【讨论】:

【参考方案4】:

如果您愿意,可以在窗口中将区域设置全局设置为 UTF-8,如下所示:

Control panel -> Clock and Region -> Region -> Administrative -> Change system locale -> 检查Beta: Use Unicode UTF-8 ...

在此之后并重新启动,我确认 locale.getpreferredencoding() 返回 'cp65001' (=UTF-8) 并且像 open 这样的函数默认为 UTF-8。

【讨论】:

以上是关于在 Windows 中更改 Python 3 中的“区域设置首选编码”的主要内容,如果未能解决你的问题,请参考以下文章

更改 Python cx_Freeze 项目中的文件夹结构

在 Windows 中更改 Python 路径

Python 3从另一个函数更改函数中的变量

在 Python 中编写适用于 Windows 中的 Python 2.7+ 和 Python 3.3+ 的 .CSV 文件

在 Python 中读取和/或更改 Windows 8 主卷 [重复]

用python编写程序?