파이썬은 비슷하게 보이는 두 개의 유니 코드 식별자를 금지합니까?


81

나는 유니 코드 식별자를 가지고 놀았고 이것을 우연히 발견했습니다.

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

여기서 무슨 일이 일어나고 있습니까? 파이썬이에서 참조하는 객체를 대체하는 이유는 무엇 𝑓입니까? 그 행동은 어디에 설명되어 있습니까?


9
이 흥미로운 질문이다,하지만 최소한의 재현 예는 단지 수 있었다𝑓=1 f=2 print(𝑓)
khelwood

1
감사. 이제 예제를 더 작게 만들었습니다.
에릭 Cederstrand


1
a, a = 1, 2; a, a. 이과는 아무 상관이 없습니다 f또는 𝑓.
user76284

4
예제로 𝑓 = 3; f충분합니다.
user76284

답변:


81

PEP 3131-비 ASCII 식별자 지원 말한다

모든 식별자는 구문 분석 중에 일반 형식 NFKC로 변환됩니다. 식별자 비교는 NFKC를 기반으로합니다.

unicodedata변환을 테스트하는 데 사용할 수 있습니다 .

import unicodedata

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

이는 파싱에서 '𝑓'변환 됨을 나타냅니다 'f'. 예상되는 결과 :

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

23
이것은 훌륭한 대답이지만 Python 핵심 개발자의 끔찍한 결정입니다. 이 PEP에 대한 논의에서 반대 중 하나는 유니 코드가 제대로 이해되지 않고 툴링이 약하다는 것이 었습니다. 10 년이 지난 지금, 유니 코드 식별자의 로마자 표기를 다시 생각할 때가되었는지 궁금합니다.
아담 스미스 (Adam Smith)

33
@AdamSmith이지만 유니 코드 정규화는 로마자 표기가 아닙니다. 괜찮은 것과 π구별되는 Python 식별자를 가질 수 있습니다 p. 내가 올바르게 이해한다면, NFK * 접기는 유니 코드 사람들이 처음에는 같은 문자 여야한다고 생각했던 문자에 관한 것이지만 일부 레거시 인코딩과의 하위 호환성 때문에 병합 할 수 없습니다.
lenz

19
문자 동등성에는 표준 및 호환성의 두 가지 종류가 있습니다. 정규 동등성은 𝑓와 f 사이의 경우가 아닌 똑같은 글리프를 렌더링해야합니다. NFKC는 표준 및 호환성 동등성을 모두 정규화합니다. 필자는 대소 문자를 구분하는 Python과 같은 프로그래밍 언어에 대해 잘못된 선택이라는 데 동의합니다. 다르게 렌더링되는 식별자는 달라야합니다. Python은 𝑓과 f가 서로 다른 것을 보장하는 NFC를 사용해야합니다.
lvella

27
예를 들어 분음 부호가있는 라틴 문자 때문에 정규화 형식이 필요합니다. 'ü'와 같은 문자가 표시되면 복합 문자 (u + 분음 조합) 또는 미리 구성된 단일 문자 일 수 있습니다. 사용자는 이들을 구별 할 합리적인 방법이나 욕구가 없으며 선호하는 입력 방법은 이러한 옵션 중 하나만 입력 할 수 있습니다. 따라서 내가 'ü'를보고 'ü'를 입력하면 NFC 정규화로 충분할 수 있지만 언어는 문자가 다르게 인코딩 되더라도 동일한 것으로 간주하는 것이 바람직합니다.
Peteris

8
파이썬은 모든 유니 코드 코드 포인트에 대한 동등한 액세스를 제공하지 않고 비 영어 언어로 식별자를 정의 할 때 사용을 용이하게하기 위해 식별자에 유니 코드를 지원합니다. 예를 들어, 현재 유니 코드 연산자를 지원하기 위해 파서를 해킹하는 것은 매우 어렵습니다. 문제의 유니 코드 문자가 식별자의 유효한 부분이 아니더라도 비 ASCII 문자가 먼저 식별자의 일부로 간주되기 때문입니다. 아이디어는 "흥미로운"문자에 대한 유니 코드 마이닝을 지원하는 것이 아니라 표준 비 영어 키보드 레이아웃에서 생성 된 문자를 지원하는 것입니다.
chepner

28

다음은이 "기능"이 얼마나 끔찍한 지 보여주는 간단한 예입니다.

𝕋𝐡ᵢ𝔰_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 𝓕𝕖𝒆𝑙 𝐟ʳ𝙚ₑ ᵗ𝗈 ᵈ𝚘 𝓈º. 나는 𝐡a𝔳ᵉ 𝒔𝚘𝙢𝖾 𝒄𝑜𝖽ᵉ 𝖑𝒶𝒚𝑖𝒏𝕘 arₒ𝘶𝘯𝖽. 𝐈 ʷ𝙖n𝓉ℯ𝙙 𝒕𝘰 𝗍𝕣o𝑙𝗅 ⅽ𝔬𝚕𝘭ᵉ𝗮𝓰𝘶𝖊𝔰 ʷ𝚒ₜ𝙝 𝓲ᵗ, 𝕓𝒖t 𝐼이 ⅈt을 ᵘ𝓼ₑⅾ ⁿ𝚎v𝖾𝔯 𝘀𝐨 𝚝ℎₑ 𝗋𝑒𝙨𝓊𝕝𝓉는 𝓳ᵘ𝑠𝙩 t𝚘𝗈 𝗵o𝒓𝑟ible ⅈ𝔰. 𝕌𝓃𝗍𝚒l 𝕟𝚘𝙬.
Eric Duminil

8
그리고 물론 : А = 42; print(A)-> "NameError : name 'A'is not defined"
Mark M

8
요점은 임의로 복잡한 식별자 이름에 대한 문을 열지 않고 프로그래머의 모국어로 식별자를 쉽게 입력하는 것입니다 (해당 언어에 고유 한 키보드 레이아웃 사용). 코드 포인트를 문자로 분류하는 유니 코드를 사용하는 것이 쓰기 시스템을 식별자로 사용할 수 있고 사용할 수없는 중재자 역할을하는 것보다 낫습니다. (그리고 단일 쓰기 시스템의 문자로 식별자를 제한하는 것은 파서의 급여 등급을 훨씬 뛰어 넘습니다.)
chepner

12
이러한 코드 포인트 중 어느 것도 자연어 작성 시스템의 일부가 아니므로 이들 중 하나라도 식별자의 일부로 허용되는지 여부는 Python 자체의 명시 적 보증보다는 유니 코드 분류에 기반한 거의 "우연적"입니다.
chepner
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.