Python 是否禁止使用两个外观相似的 Unicode 标识符?

87

我正在尝试使用Unicode标识符,并偶然发现了这个:

>>> , x = 1, 2
>>> , x
(1, 2)
>>> , f = 1, 2
>>> , f
(2, 2)

这里发生了什么?为什么Python有时会替换被引用的对象?这种行为在哪里描述?


10
这是一个有趣的问题,但是你的[mre]可能只需要写成=1f=2print()就可以了。 - khelwood
1
谢谢。现在将示例缩小了。 - Erik Cederstrand
37
obxkcd - Barmar
1
a, a = 1, 2; a, a。这与f或``无关。 - user76284
4
例子 = 3; f 就足够了。 - user76284
2个回答

87
< p > PEP 3131 -- 支持非ASCII标识符 表示:

所有标识符在解析时都会被转换为正常形式NFKC;标识符的比较基于NFKC。

您可以使用unicodedata测试转换结果:

import unicodedata

unicodedata.normalize('NFKC', '')
# f

这表明在解析中''被转换为'f'。因此得到了期望的结果:
  = "Some String"
print(f)
# "Some String"

26
这是一个很好的回答,但Python核心开发人员的决定很糟糕。我注意到,在讨论这个PEP时,有一个反对意见是Unicode的理解不足,并且工具不够强大。现在,十年过去了,我想知道是否该重新考虑Unicode标识符的罗马化。 - Adam Smith
36
@AdamSmith 但 Unicode 正规化并非罗马字母转写。你可以在 Python 标识符中使用 π,而不会与 p 发生混淆。如果我理解正确,NFK* 折叠是关于 Unicode 尝试将某些字符归为同一字符,但由于与一些旧编码的向后兼容性问题无法合并。 - lenz
21
字符等价性分为两种:规范等价性和兼容等价性。规范等价性应该呈现完全相同的字形,但在 和 f 之间并非如此。NFKC 正规化了规范等价性和兼容等价性,我认为这对于像 Python 这样的编程语言来说是一个糟糕的选择,因为它区分字母大小写:预期呈现不同的标识符应该是不同的。Python 应该使用 NFC,它确保 和 f 是不同的东西。 - lvella
30
由于例如带有变音符的拉丁字符,需要某种形式的规范化 - 如果我看到类似'ü'的字符,则它可能是组合字符(u + 合成分音符),也可能是预组合的单个字符;用户没有合理的方法或愿望来区分它们,并且他们首选的输入法可能只允许输入其中一种选项。因此,如果我看到'ü'并键入'ü',则希望语言将这些字符视为等效,即使它们以不同的方式编码,但NFC规范化可能已经足够了。 - Peteris
10
Python支持使用Unicode作为标识符,以便于在非英语语言中定义标识符,而不是为了让所有Unicode码点都能够平等地被访问。例如,目前很难通过修改解析器来支持Unicode运算符,因为任何非ASCII字符都会首先被假定为标识符的一部分,即使该Unicode字符不是标识符的有效组成部分。这个想法不是为了支持挖掘Unicode中的“有趣”字符,而是为了支持标准的非英语键盘布局所产生的字符。 - chepner
显示剩余3条评论

31
这里有一个小例子,只是为了展示这个“特性”有多糟糕:

ᵢ_fᵣₑ_ₕ_dₑᵢiℓy___ᵘg = 42
print(Tℹ_eᵣe_ₛº_eᵢⁱtᵉ_ℯ__)
# => 42
在线试用!(但请不要使用它)
正如@MarkMeyer所提到的,尽管两个标识符看起来完全相同(“CYRILLIC CAPITAL LETTER A”和“LATIN CAPITAL LETTER A”),但它们可能是不同的。
А = 42
print(A)
# => NameError: name 'A' is not defined

3
让我想写一个jsfuck.com的等价物... python-unicode-hell.com? - Mathieu VIALES
2
@MathieuVIALES ʳₑ ᵗ ᵈ º. 我是程序员。当我写代码时,经常会遇到问题。但是我喜欢解决它们。 - Eric Duminil
8
当然,然后:А = 42; print(A) --> "NameError: name 'A' is not defined"。 - Mark
10
重点并非为了开启任意复杂的标识符名称,而是为了方便程序员使用其本地语言键盘布局输入标识符。最好按照Unicode将代码点分类为字母,而不是充当哪些书写系统可以和不能用于标识符的仲裁者。(限制标识符只能由单一书写系统的字符组成远超出解析器的工资等级。) - chepner
13
这些代码点都不属于任何自然语言的书写系统,因此它们是否可以作为标识符的一部分几乎是“偶然”的,取决于Unicode分类而不是Python本身的明确认可。 - chepner
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接