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


81

我在玩Unicode标识符,偶然发现了这一点:

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

这里发生了什么?为什么Python会替换引用的对象𝑓,但有时会替换呢?该行为在哪里描述?


9
这是一个有趣的问题,但是您的最小可重现示例可能只是𝑓=1 f=2 print(𝑓)
khelwood

1
谢谢。现在使示例变得更小。
Erik Cederstrand


1
a, a = 1, 2; a, a。这与f或无关𝑓
user76284年

4
该示例𝑓 = 3; f就足够了。
user76284年

Answers:


81

PEP 3131-支持非ASCII标识符

解析时,所有标识符都转换为标准形式NFKC;标识符的比较基于NFKC。

您可以unicodedata用来测试转换:

import unicodedata

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

这表示在解析中将'𝑓'转换为'f'。导致预期:

𝑓  = "Some String"
print(f)
# "Some String"

23
这是一个很好的答案,但Python核心开发人员做出了一个糟糕的决定。我注意到在讨论此PEP时,反对意见之一是Unicode的理解不充分,并且工具功能较弱。现在,在十多年后的今天,我想知道是否该重新考虑Unicode标识符的罗马化了。
亚当·斯密

33
@AdamSmith,但是Unicode规范化不是罗马化。π作为Python标识符,您可以拥有与众不同的标识符p。如果我理解正确,则NFK *折叠与Unicode人们认为应该以相同的字符开头的字符有关,但由于与某些旧编码的向后兼容性,它们无法合并。
lenz

19
有两种等效的字符:规范和兼容性。规范等价应呈现完全相同的字形,𝑓和f之间不是这种情况。NFKC规范化规范和兼容性等价,我同意这对于像Python这样的编程语言来说是一个糟糕的选择,Python区分字母大小写:期望呈现不同的标识符应该不同。Python应该使用NFC,这可以确保𝑓和f是不同的东西。
lvella

27
例如由于拉丁字母带有变音符号的字符,因此需要某种形式的规范化-如果我看到类似“ü”的字符,则它可能是复合字符(u +组合音调)或预先组合的单个字符;用户将没有合理的方式或愿望来区分它们,并且他们的首选输入法可能仅允许输入这些选项之一。因此,希望我看到“ü”并键入“ü”,然后即使它们的编码方式不同,该语言也将其视为等效字符,尽管NFC规范化可能就足够了。
Peteris

8
Python支持将Unicode用于标识符,以便于在非英语语言中定义标识符时使用它,而不是提供对所有Unicode代码点的平等访问。例如,目前很难破解解析器以支持Unicode运算符,因为首先假定任何非ASCII字符都是标识符的一部分,即使所讨论的Unicode字符不是标识符的有效部分也是如此。这个想法不是支持挖掘“有趣”字符的Unicode,而是支持标准非英语键盘布局产生的字符。
chepner

28

这是一个小示例,仅用于说明此“功能”有多可怕:

𝕋𝐡ᵢ𝔰_f𝔢𝘢𝚝𝓊ᵣₑ_𝕤ₕ𝔬𝔲𝖑𝔡_dₑ𝕗ᵢ𝘯i𝘵𝚎ℓy_𝒷𝘦_𝐚_𝚋ᵘg = 42
print(T𝗵ℹ𝚜_𝒇e𝖆𝚝𝙪ᵣe_ₛ𝔥º𝓾𝗹𝙙_𝚍e𝒇ᵢ𝒏ⁱtᵉ𝕝𝘆_𝖻ℯ_𝔞_𝖇𝖚𝓰)
# => 42

在线尝试!(但是请不要使用它)

而且,正如@MarkMeyer所提到的,即使两个标识符看起来相同,它们也可能是不同的(“西里尔大写字母A”和“拉丁大写字母A”)

А = 42
print(A)
# => NameError: name 'A' is not defined

3
让我想写一个相当于jsfuck.com ... python-unicode-hell.com吗?
Mathieu VIALES

2
@MathieuVIALES𝓕𝕖𝒆𝑙𝓈𝓈ºº。我𝐡a𝔳ᵉ。𝓲ᵗʷ𝙖𝓉ℯ𝙙𝑙𝗅𝑙𝗅𝑙𝗅𝓲ᵗ𝓲ᵗ𝓲ᵗ。𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯𝖾𝔯ⅈ。𝕌𝓃𝗍𝚒。
埃里克·杜米尼尔

8
然后当然:А = 42; print(A)->“ NameError:未定义名称'A'”
Mark M

8
关键不是要打开任意复杂的标识符名称的大门,而是要方便以程序员的母语(使用该语言的键盘布局)键入标识符。最好将Unicode将代码点分类为字母而不是充当仲裁器,以使书写系统可以或不能将其用作标识符。(并且将标识符限制为来自单个书写系统的字符远远超出了解析器的薪水等级。)
chepner

12
这些代码点都不是任何自然语言编写系统的一部分,因此,根据Unicode分类,而不是由Python本身进行任何明确认可,它们中的任何一个点是否可以作为标识符的一部分都几乎是“偶然的”。
chepner
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.