Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 686 – 默认启用 UTF-8 模式

作者:
稻田直树 <songofacandy at gmail.com>
讨论至:
Discourse 帖子
状态:
已接受
类型:
标准跟踪
创建日期:
2022 年 3 月 18 日
Python 版本:
3.15
发布历史:
2022 年 3 月 18 日, 2022 年 3 月 31 日
决议:
Discourse 消息

目录

摘要

此 PEP 提议默认启用 UTF-8 模式

通过此更改,Python 将始终使用 UTF-8 作为文件、标准输入输出和管道的默认编码。

动机

UTF-8 成为事实上的标准文本编码。

  • Python 源文件的默认编码是 UTF-8。
  • JSON、TOML、YAML 使用 UTF-8。
  • 大多数文本编辑器,包括 Visual Studio Code 和 Windows 记事本,默认使用 UTF-8。
  • 互联网上的大多数网站和文本数据都使用 UTF-8。
  • 许多其他流行的编程语言,包括 Node.js、Go、Rust 和 Java,默认都使用 UTF-8。

将默认编码更改为 UTF-8 使 Python 更容易与它们进行互操作。

此外,许多使用 Unix 的 Python 开发人员忘记了默认编码是平台相关的。他们在读取 UTF-8 编码的文本文件(例如 JSON、TOML、Markdown 和 Python 源文件)时,省略了指定 encoding="utf-8"。不一致的默认编码会导致许多错误。

规范

默认启用 UTF-8 模式

Python 将从 Python 3.15 开始默认启用 UTF-8 模式。

用户仍可以通过设置 PYTHONUTF8=0-X utf8=0 来禁用 UTF-8 模式。

locale.getencoding()

由于 UTF-8 模式会影响 locale.getpreferredencoding(False),因此我们需要一种 API 来获取区域设置编码,而忽略 UTF-8 模式。

为此将添加 locale.getencoding()。它也会返回区域设置编码,但会忽略 UTF-8 模式。

当指定 warn_default_encoding 选项时,locale.getpreferredencoding() 将发出 EncodingWarning,就像 open() 一样(另请参阅 PEP 597)。

此 API 已在 Python 3.11 中添加。

修复 encoding="locale" 选项

PEP 597TextIOWrapper 添加了 encoding="locale" 选项。此选项用于显式指定区域设置编码。当指定此选项时,TextIOWrapper 应使用区域设置编码,而忽略默认文本编码。

但目前,即使指定了 encoding="locale"TextIOWrapper 在 UTF-8 模式下仍使用 "UTF-8"。此行为与 PEP 597 的初衷不符。这是因为我们在 Python 更改其默认文本编码时,并未预料到会默认启用 UTF-8 模式。

在默认启用 UTF-8 模式之前,应修复此不一致性。即使在 UTF-8 模式下,当传入 encoding="locale" 时,TextIOWrapper 也应使用区域设置编码。

此问题已在 Python 3.11 中修复。

向后兼容性

大多数 Unix 系统使用 UTF-8 区域设置,Python 在其区域设置为 C 或 POSIX 时启用 UTF-8 模式。因此,此更改主要影响 Windows 用户。

当 Python 程序依赖于默认编码时,此更改可能导致 UnicodeError、乱码,甚至静默数据损坏。因此,应大声宣布此更改。

这是修复此向后兼容性问题的指南

  1. 禁用 UTF-8 模式。
  2. 使用 EncodingWarningPEP 597)查找 UTF-8 模式影响的所有位置。
    • 如果省略了 encoding 选项,请考虑使用 encoding="utf-8"encoding="locale"
    • 如果使用了 locale.getpreferredencoding(),请考虑使用 "utf-8"locale.getencoding()
  3. 测试应用程序在 UTF-8 模式下的运行情况。

先前的示例

  • Ruby 在 Ruby 3.0 (2020) 中 更改了 Windows 上的默认 external_encoding 为 UTF-8。
  • Java 在 JDK 18 (2022) 中 更改了默认文本编码为 UTF-8。

Ruby 和 Java 都提供了向后兼容的选项。它们不提供类似 Python 中 PEP 597EncodingWarning 来警告使用默认编码。

否决的替代方案

弃用隐式编码

考虑弃用默认编码的使用。

但有很多情况是默认编码仅用于读取/写入 ASCII 文本。此外,对于在 Unix 上运行的非跨平台应用程序,此类警告没有用处。

因此,强制用户在所有地方指定 encoding 会非常痛苦。发出大量 DeprecationWarning 会导致用户忽略警告。

PEP 387 要求为向后不兼容的更改添加警告。但它不要求使用 DeprecationWarning。因此,使用可选的 EncodingWarning 不会违反 PEP 387

Java 也在 JEP 400 中拒绝了此想法。

为管道使用 PYTHONIOENCODING

为了缓解向后兼容性问题,考虑在 subprocess 模块中将 PYTHONIOENCODING 用作管道的默认编码。

通过此想法,用户即使在 UTF-8 模式下,也可以为 subprocess.Popen(text=True) 使用旧的编码。

但这个想法使“默认编码”变得复杂。并且这个想法也是向后不兼容的。

因此,此想法被否决。用户可以在将 text=True 替换为 encoding="utf-8"encoding="locale" 之前禁用 UTF-8 模式。

如何教授

对于新用户来说,此更改减少了需要教授的内容。用户不需要在第一年就学习文本编码。当他们需要使用非 UTF-8 文本文件时,才应该学习它。

对于现有用户,请参阅 向后兼容性 部分。


来源:https://github.com/python/peps/blob/main/peps/pep-0686.rst

最后修改:2025-02-01 08:55:40 GMT