Following system colour scheme Selected dark colour scheme Selected light colour scheme

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字符存储在磁盘上并在网络上传输。
代理对
表示单个逻辑字符的两个物理字符。表示32位码位为两个16位码位的一种约定的一部分。
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世界中有一种约定,用于将32位码位编码为两个16位码位。这些称为“代理对”。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的宽度。

基于很少有人请求宽字符这一事实,Windows构建在一段时间内将保持窄状态,这些请求主要来自能够购买自己的Python的资深程序员,并且Windows本身也强烈偏向于16位字符。

注释

此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

上次修改:2023-09-09 17:39:29 GMT