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


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.