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

Python 增强提案

PEP 261 – 支持“宽”Unicode 字符

作者:
Paul Prescod <paul at prescod.net>
状态:
最终版
类型:
标准跟踪
创建日期:
2001年6月27日
Python 版本:
2.2
发布历史:
2001年6月27日

目录

摘要

Python 2.1 的 Unicode 字符的序数最大只能到 2**16 - 1。这个范围对应于 Unicode 中被称为基本多语言平面的范围。现在 Unicode 中有位于其他“平面”的字符。Unicode 中可寻址的最大字符的序数是 17 * 2**16 - 1 (0x10ffff)。为便于阅读,我们称之为 TOPCHAR,并称此范围内的字符为“宽字符”。

词汇表

字符
单独使用时,指 Python Unicode 字符串的可寻址单元。
码位
码位是一个介于 0 和 TOPCHAR 之间的整数。如果你将 Unicode 想象成整数到字符的映射,每个整数就是一个码位。但是 0 到 TOPCHAR 之间不映射到字符的整数也是码位。有些将来会被用于字符。有些则保证永远不会被用于字符。
编解码器
一组用于在物理编码(例如,在磁盘上或从网络传入)和逻辑 Python 对象之间进行转换的函数。
编码
以物理位和字节表示抽象字符的机制。编码允许我们以与其他 Unicode 软件兼容的方式,将 Unicode 字符存储在磁盘上并通过网络传输。
代理对
表示单个逻辑字符的两个物理字符。它是以两个 16 位码位表示 32 位码位约定的一部分。
Unicode 字符串
一种 Python 类型,表示具有“字符串语义”(例如,大小写转换、正则表达式兼容性等)的码位序列。使用 unicode() 函数构造。

提议的解决方案

一种解决方案是仅仅将最大序数增加到一个更大的值。不幸的是,这种想法唯一直接的实现是每个字符使用 4 字节。这会使大多数 Unicode 字符串的大小加倍。为了避免给每个用户带来这种成本,Python 2.2 将允许 4 字节实现作为构建时选项。用户可以选择他们是否关心宽字符或更愿意保留内存。

4 字节选项称为“宽 Py_UNICODE”。2 字节选项称为“窄 Py_UNICODE”。

在宽和窄两种模式下,大多数行为都将相同。

  • unichr(i) 对于 0 <= i < 2**16 (0x10000) 总是返回长度为一的字符串。
  • unichr(i) 对于 2**16 <= i <= TOPCHAR,在宽 Python 构建上将返回长度为一的字符串。在窄构建上,它将引发 ValueError

    问题

    Python 目前允许 \U 字面量,这些字面量无法表示为单个 Python 字符。它会生成两个 Python 字符,称为“代理对”。这是否应在未来的窄 Python 构建中被禁止?

    支持

    Python 已经允许为大型 Unicode 字面量字符转义序列构造代理对。这基本上被设计为一种简单的方法,即使在窄 Python 构建中也能构造“宽字符”。考虑到 Unicode 字面量语法基本上是调用 unicode-escape 编解码器的简写形式,这在某种程度上也是符合逻辑的。

    反对

    代理可以很容易地通过这种方式创建,但用户仍然需要小心切片、索引、打印等。因此,有人建议 Unicode 字面量不应支持代理。

    问题

    Python 是否应该允许构造与 Unicode 码位不对应的字符?未分配的 Unicode 码位显然应该是合法的(因为它们可能随时被分配)。但高于 TOPCHAR 的码位保证永远不会被 Unicode 使用。我们是否应该允许访问它们?

    支持

    如果 Python 用户认为他们知道自己在做什么,我们为什么要阻止他们违反 Unicode 规范?毕竟,我们不会阻止 8 位字符串包含非 ASCII 字符。

    反对

    编解码器和其他使用 Unicode 的代码将不得不小心这些 Unicode 规范不允许的字符。
  • ord() 总是 unichr() 的逆运算
  • sys 模块中有一个整数值,描述了当前解释器上 Unicode 字符串中字符的最大序数。sys.maxunicode 在 Python 的窄构建上是 2**16-1 (0xffff),在宽构建上是 TOPCHAR。

    问题

    是否应该有不同的常量来访问 TOPCHAR 和 unichr 域的实际上限(如果它们不同)?还有人建议使用 sys.unicodewidth,它可以取值 'wide''narrow'
  • 每个 Python Unicode 字符精确地表示一个 Unicode 码位(即 Python Unicode 字符 = 抽象 Unicode 字符)。
  • 编解码器将升级以支持“宽字符”(直接用 UCS-4 表示,以及用 UTF-8 和 UTF-16 表示为可变长度序列)。这是实施中最重要的部分。
  • 在 Unicode 世界中,有一种约定,用两个 16 位码位来编码一个 32 位码位。这些被称为“代理对”。Python 的编解码器将采用此约定,并在窄 Python 构建上将 32 位码位编码为代理对。

    问题

    是否应该有一种方法告诉编解码器不要生成代理,而是将宽字符视为错误?

    支持

    我可能想编写只处理定宽字符且不必担心代理的代码。

    反对

    目前尚无明确的提案说明如何将此信息传达给编解码器。
  • 构造不当使用“为代理保留”的码位的字符串没有任何限制。这些被称为“孤立代理”。编解码器应该禁止从文件中读取这些字符,但您可以使用字符串字面量或 unichr() 来构造它们。

实施

有一个新的定义

#define Py_UNICODE_SIZE 2

要测试正在使用 UCS2 还是 UCS4,应使用派生宏 Py_UNICODE_WIDE,当使用 UCS-4 时定义此宏。

有一个新的配置选项

--enable-unicode=ucs2 配置窄 Py_UNICODE,如果 wchar_t 适合则使用它
--enable-unicode=ucs4 配置宽 Py_UNICODE,如果 wchar_t 适合则使用它
--enable-unicode 与“=ucs2”相同
--disable-unicode 完全移除 Unicode 功能。

还建议有一天 --enable-unicode 将默认使用您平台 wchar_t 的宽度。

由于对宽字符的需求很少,而且这些需求大多来自有能力购买自己的 Python 的核心程序员,加上 Windows 本身强烈倾向于 16 位字符,因此 Windows 构建将暂时保持窄模式。

备注

本 PEP 并不意味着使用 Unicode 的人必须为其磁盘上的文件或通过网络发送的文件使用 4 字节编码。它只是允许他们这样做。例如,ASCII 仍然是一种合法的(7 位)Unicode 编码。

有人提议应该有一个模块,在窄 Python 构建中为程序员处理代理。如果有人想实现这一点,那将是另一个 PEP。它也可能与允许其他类型的字符、单词和行索引的功能相结合。

被拒绝的建议

或多或少保持现状

我们可以官方声明 Python 字符是 16 位的,并要求程序员通过组合代理对在其应用程序逻辑中实现宽字符。这是一个沉重的负担,因为如果完全用 Python 编写,模拟 32 位字符可能会非常低效。此外,这些抽象的伪字符串作为正则表达式引擎的输入将是不合法的。

“节省空间的 Unicode”类型

另一类解决方案是在内部使用一些高效的存储,但向程序员呈现宽字符的抽象。其中任何一种都需要比接受的解决方案更复杂的实现。例如,考虑对正则表达式引擎的影响。理论上,我们可以在未来转向这种实现,而不会破坏 Python 代码。未来的 Python 可以在窄 Python 上“模拟”宽 Python 语义。Guido 不愿意现在着手实现。

两种类型

我们可以引入一个 32 位 Unicode 类型,与 16 位类型并存。有很多代码期望只有一个 Unicode 类型。

本 PEP 代表了最省力的解决方案。在未来几年,32 位 Unicode 字符将变得更加普遍,这可能使我们相信我们需要一个更复杂的解决方案,或者(另一方面)使我们相信简单地强制使用宽 Unicode 字符是一个合适的解决方案。目前摆在桌面上的两个选择是:什么都不做,或者做这个。

参考资料

Unicode 词汇表:http://www.unicode.org/glossary/


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

最后修改:2025-02-01 08:59:27 GMT