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

Python 增强提案

PEP 624 – 移除 Py_UNICODE 编码器 API

作者:
稻田直树 <songofacandy at gmail.com>
状态:
最终版
类型:
标准跟踪
创建日期:
2020年7月6日
Python 版本:
3.11
发布历史:
2020年7月8日

目录

摘要

本 PEP 提议在 Python 3.11 中移除已弃用的 Py_UNICODE 编码器 API

  • PyUnicode_Encode()
  • PyUnicode_EncodeASCII()
  • PyUnicode_EncodeLatin1()
  • PyUnicode_EncodeUTF7()
  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()
  • PyUnicode_EncodeUTF32()
  • PyUnicode_EncodeUnicodeEscape()
  • PyUnicode_EncodeRawUnicodeEscape()
  • PyUnicode_EncodeCharmap()
  • PyUnicode_TranslateCharmap()
  • PyUnicode_EncodeDecimal()
  • PyUnicode_TransformDecimalToASCII()

注意

PEP 623 提议移除与 Py_UNICODE 相关的 Unicode 对象 API。另一方面,本 PEP 与 Unicode 对象无关。这些 PEP 之所以分开,是因为它们有不同的动机,需要不同的讨论。

动机

总的来说,减少长期弃用且用户较少的 API 数量是个好主意,因为它不仅提高了 CPython 的可维护性,还有助于 API 用户和其他 Python 实现。

基本原理

自 Python 3.3 起已弃用

Py_UNICODE 及使用它的 API 自 Python 3.3 起已弃用。

效率低下

所有这些 API 都使用 PyUnicode_FromWideChar 实现。因此,当用户想要编码 Unicode 对象时,这些 API 效率低下。

使用不广泛

在搜索排名前 4000 的 PyPI 包 [1] 时,只有 pyodbc 使用这些 API。

  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()

pyodbc 使用这些 API 将 Unicode 对象编码为字节对象。因此很容易修复。[2]

替代 API

存在接受 PyObject *unicode 而非 Py_UNICODE * 的替代 API。用户可以迁移到它们。

已弃用 API 替代 API
PyUnicode_Encode() PyUnicode_AsEncodedString()
PyUnicode_EncodeASCII() PyUnicode_AsASCIIString() (1)
PyUnicode_EncodeLatin1() PyUnicode_AsLatin1String() (1)
PyUnicode_EncodeUTF7() (2)
PyUnicode_EncodeUTF8() PyUnicode_AsUTF8String() (1)
PyUnicode_EncodeUTF16() PyUnicode_AsUTF16String() (3)
PyUnicode_EncodeUTF32() PyUnicode_AsUTF32String() (3)
PyUnicode_EncodeUnicodeEscape() PyUnicode_AsUnicodeEscapeString()
PyUnicode_EncodeRawUnicodeEscape() PyUnicode_AsRawUnicodeEscapeString()
PyUnicode_EncodeCharmap() PyUnicode_AsCharmapString() (1)
PyUnicode_TranslateCharmap() PyUnicode_Translate()
PyUnicode_EncodeDecimal() (4)
PyUnicode_TransformDecimalToASCII() (4)

备注

  1. 缺少 const char *errors 参数。
  2. 没有公共替代 API。但用户可以使用通用的 PyUnicode_AsEncodedString() 代替。
  3. 缺少 const char *errors, int byteorder 参数。
  4. 没有直接替代。但可以使用 Py_UNICODE_TODECIMAL 代替。CPython 使用 _PyUnicode_TransformDecimalAndSpaceToASCII 进行 Unicode 到数字的转换。

计划

在 Python 3.11 中移除这些 API。它们已弃用。

  • PyUnicode_Encode()
  • PyUnicode_EncodeASCII()
  • PyUnicode_EncodeLatin1()
  • PyUnicode_EncodeUTF7()
  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()
  • PyUnicode_EncodeUTF32()
  • PyUnicode_EncodeUnicodeEscape()
  • PyUnicode_EncodeRawUnicodeEscape()
  • PyUnicode_EncodeCharmap()
  • PyUnicode_TranslateCharmap()
  • PyUnicode_EncodeDecimal()
  • PyUnicode_TransformDecimalToASCII()

替代方案

Py_UNICODE* 替换为 PyObject*

如“替代 API”部分所述,某些 API 没有接受 PyObject *unicode 输入的公共替代 API。并且某些公共替代 API 存在限制,例如缺少 errorsbyteorder 参数。

我们可以重用已弃用 API 的名称作为替代公共 API,而不是移除它们。

由于我们已有私有替代 API,因此只是将私有名称重命名为公共名称和已弃用名称。

重命名为 重命名自
PyUnicode_EncodeASCII() _PyUnicode_AsASCIIString()
PyUnicode_EncodeLatin1() _PyUnicode_AsLatin1String()
PyUnicode_EncodeUTF7() _PyUnicode_EncodeUTF7()
PyUnicode_EncodeUTF8() _PyUnicode_AsUTF8String()
PyUnicode_EncodeUTF16() _PyUnicode_EncodeUTF16()
PyUnicode_EncodeUTF32() _PyUnicode_EncodeUTF32()

优点

  • 我们拥有更一致的 API 集。

缺点

  • 向后不兼容。
  • 我们需要为不常用的情况维护更多公共 API。
  • 现有的公共 API 足以满足大多数用例,PyUnicode_AsEncodedString() 可用于其他情况。

Py_UNICODE* 替换为 Py_UCS4*

我们可以将 Py_UNICODE 替换为 Py_UCS4 并取消弃用这些 API。

UTF-8、UTF-16、UTF-32 编码器内部支持 Py_UCS4。因此 PyUnicode_EncodeUTF8()PyUnicode_EncodeUTF16()PyUnicode_EncodeUTF32() 可以避免创建临时 Unicode 对象。

优点

  • 当使用 UTF-8、UTF-16、UTF-32 编解码器将 Py_UCS4* 编码为字节对象时,我们可以避免创建临时 Unicode 对象。

缺点

  • 向后不兼容。
  • 我们需要为不常用的情况维护更多公共 API。
  • 其他希望支持 Python/C API 的 Python 实现也需要支持这些 API。
  • 如果我们将来将 Unicode 内部表示更改为 UTF-8,我们只需要为这些 API 保留 UCS-4 支持。

Py_UNICODE* 替换为 wchar_t*

我们可以将 Py_UNICODE 替换为 wchar_t。由于 Py_UNICODE 已经是 wchar_t 的 typedef,所以这是现状。

sizeof(wchar_t) == 4 的平台上,当使用 UTF-8、UTF-16 和 UTF-32 编解码器将 wchar_t* 编码为字节对象时,我们可以避免创建临时 Unicode 对象,就像“将 Py_UNICODE* 替换为 Py_UCS4*”的思路一样。

优点

  • 向后兼容。
  • sizeof(wchar_t) == 4 的平台上,当使用 UTF-8、UTF-16、UTF-32 编解码器将 Py_UCS4* 编码为字节对象时,我们可以避免创建临时 Unicode 对象。

缺点

  • 尽管 Windows 是大量使用 wchar_t 的主要平台,但这些 API 总是需要创建临时 Unicode 对象,因为 Windows 上 sizeof(wchar_t) == 2
  • 我们需要为不常用的情况维护更多公共 API。
  • 其他希望支持 Python/C API 的 Python 实现也需要支持这些 API。
  • 如果我们将来将 Unicode 内部表示更改为 UTF-8,我们只需要为这些 API 保留 UCS-4 支持。

被拒绝的想法

发出运行时警告

除了现有的编译器警告,建议发出运行时 DeprecationWarning

但这些 API 目前不释放 GIL。从这样的 API 发出警告是不安全的。请看这个例子。

PyObject *u = PyList_GET_ITEM(list, i);  // u is borrowed reference.
PyObject *b = PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(u),
        PyUnicode_GET_SIZE(u), NULL);
// Assumes u is still living reference.
PyObject *t = PyTuple_Pack(2, u, b);
Py_DECREF(b);
return t;

如果我们从 PyUnicode_EncodeUTF8() 发出 Python 警告,警告过滤器和其他线程可能会改变 list,并且在 PyUnicode_EncodeUTF8() 返回后,u 可能成为悬空引用。

讨论

反对意见

  • 移除这些 API 会失去无需临时 Unicode 即可使用编解码器的能力。
    • 自 Python 3.3 起,编解码器无法直接编码 Unicode 缓冲区而无需临时 Unicode 对象。所有这些 API 目前都会创建临时 Unicode 对象。因此,移除它们不会降低任何能力。
  • 为什么不也移除解码器 API?
    • 它们是稳定 ABI 的一部分。
    • PyUnicode_DecodeASCII()PyUnicode_DecodeUTF8() 被广泛使用。弃用它们不值得。
    • 解码器 API 可以直接从字节缓冲区解码,而无需创建临时字节对象。另一方面,编码器 API 无法避免临时 Unicode 对象。

参考资料


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

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