PEP 223 – \x 이스케이프의 의미 변경
- Author:
- Tim Peters <tim.peters at gmail.com>
- Status:
- Final
- Type:
- Standards Track
- Created:
- 20-Aug-2000
- Python-Version:
- 2.0
- Post-History:
- 23-Aug-2000
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
8비트 문자열과 유니코드 문자열 모두에서 \x 이스케이프가 뒤따르는 16진수 숫자를 정확히 두 개만 소비하도록 변경합니다. 이 제안은 이를 원래 설계의 결함을 바로잡는 것으로 보며, 이를 통해 모든 종류의 문자열에서 표현이 더 명확해지고, 유니코드 처리 방식이 더 깔끔해지며, Perl 정규 표현식과의 호환성이 향상되고, 기존 코드에 미치는 위험은 최소화됩니다.
문법
모든 종류의 비-raw 문자열에서 \x 이스케이프의 문법은 다음과 같이 바뀝니다
\xhh
여기서 h는 16진수 숫자(0-9, a-f, A-F)입니다. 1.5.2의 정확한 문법은 참조 매뉴얼에 명확하게 명시되어 있지 않습니다. 매뉴얼에는 다음과 같이 쓰여 있습니다
\xhh...
이는 “두 개 이상”의 16진수 숫자를 암시하지만, 1.5.2 컴파일러는 한 자리 형식도 받아들이며, 단독 \x는 자기 자신으로(즉, 백슬래시 뒤에 문자 x가 오는 형태로) “확장”됩니다. 레퍼런스 매뉴얼이 한 자리 동작이나 0자리 동작을 의도했는지는 분명하지 않습니다.
의미론
8비트 비 원시 문자열에서,
\xij
다음 문자로 확장됩니다
chr(int(ij, 16))
이는 1.6 및 그 이전 버전과 동일하다는 점에 유의하십시오.
유니코드 문자열에서,
\xij
다음과 동일하게 동작합니다
\u00ij
즉, 유니코드 공간의 첫 구간에 있는 해당 Latin-1 문자로 확장됩니다.
뒤에 16진수 숫자가 최소 두 개 오지 않는 \x는 컴파일 시간 오류이며, 구체적으로 8비트 문자열에서는 ValueError, 유니코드 문자열에서는 ValueError의 서브클래스인 UnicodeError입니다. \x 뒤에 16진수 숫자가 세 개 이상 오면 처음 두 개만 “소비”된다는 점에 유의하십시오. 1.6 및 그 이전 버전에서는 마지막 두 개를 제외한 모든 숫자가 조용히 무시되었습니다.
예시
1.5.2에서:
>>> "\x123465" # same as "\x65"
'e'
>>> "\x65"
'e'
>>> "\x1"
'\001'
>>> "\x\x"
'\\x\\x'
>>>
2.0에서:
>>> "\x123465" # \x12 -> \022, "3456" left alone
'\0223456'
>>> "\x65"
'e'
>>> "\x1"
[ValueError is raised]
>>> "\x\x"
[ValueError is raised]
>>>
역사와 근거
\x 이스케이프는 C에서 가변 폭 문자 인코딩을 지정하는 방법으로 도입되었습니다. 그것이 정확히 어떤 인코딩이었는지, 그리고 16진수 숫자가 몇 개 필요한지는 각 구현에 맡겨졌습니다. 언어 명세는 단지 \x가 뒤따르는 모든 16진수 숫자를 “소비”한다고만 명시했고, 그 의미는 각 구현에 맡겼습니다. 따라서 사실상 C의 \x는 플랫폼이 정의하는 동작을 제공하기 위한 표준 훅입니다.
Python은 명시적으로 플랫폼 독립성을 목표로 하므로, Python(1.6까지 포함)의 \x 이스케이프는 모든 플랫폼에서 동일하게 처리되어 왔습니다. 마지막 두 자리 16진수 숫자를 제외한 나머지는 모두 조용히 무시되었습니다. 따라서 Python에서 \x 이스케이프의 유일한 실제 용도는 16진수 표기법으로 단일 바이트를 지정하는 것이었습니다.
Larry Wall은 이것이 플랫폼 독립적인 언어에서 \x 이스케이프의 유일한 실제 용도라는 점을 깨달았던 것으로 보입니다. Python 2.0에 제안된 규칙이 사실 Perl이 처음부터 해 온 방식이기 때문입니다(다만 뒤따르는 16진수 숫자가 2자리보다 적은 \x 이스케이프에 대해 경고를 받으려면 Perl을 -w 모드로 실행해야 합니다. 항상 2자리를 요구하는 쪽이 분명히 더 Python답습니다).
Python에 유니코드 문자열이 도입되었을 때, \x는 유니코드 문자열에서 마지막 네 자리를 제외한 모든 16진수 숫자를 무시하도록 일반화되었습니다. 이 때문에 새로운 정규 표현식 엔진에 기술적인 어려움이 생겼습니다. SRE는 8비트와 유니코드 패턴 및 문자열을 직관적인 방식으로 섞어 쓸 수 있도록 무척 애쓰는데, 예를 들어 r"\x123456"이 패턴으로서 무엇을 뜻해야 하는지 더 이상 추측할 방법이 없었습니다. 8비트 문자 \x56과 일치시키라는 것입니까, 아니면 유니코드 문자 \u3456과 일치시키라는 것입니까?
억지스럽게 추측하는 방법이 있기는 하지만, 문제는 거기서 끝나지 않습니다. ISO C99 표준은 ISO 10646 문자 공간 전체를 다루기 위해 8자리 \U12345678 이스케이프도 도입하며, Python 2도 처음부터 이를 지원하는 것이 바람직합니다. 그렇다면 \x 이스케이프는 무엇을 뜻해야 합니까? 그러면 마지막 여덟 자리를 제외한 모든 16진수 자릿수를 무시합니까? 그리고 유니코드 문자열에서 뒤따르는 자릿수가 8개보다 적으면 마지막 4자리를 제외한 전부를 무시합니까? 또 4개보다 적으면 마지막 2자리를 제외한 전부를 무시합니까?
상황은 시시각각 더 복잡해지고 있었고, 이 제안은 \x를 더 복잡하게 만드는 대신 더 단순하게 만듦으로써 고르디우스의 매듭을 끊습니다. 유니코드 문자열에서 \xijkl로 4자리 일반화를 한 것 역시 불필요했다는 점에 유의하십시오. 유니코드 문자열에서 \uijkl과 정확히 같은 의미였기 때문입니다. 16진수 표기법으로 유니코드 문자를 지정하는 명백한 방법이 단 하나만 있는 것이 더 Python답습니다.
개발 및 논의
이 제안은 Guido van Rossum, Fredrik Lundh, Tim Peters가 이메일로 논의하여 마련했습니다. 이후 2000-08-03부터 Python-Dev에서 “Go x yourself” [1]라는 제목으로 설명되고 논의되었습니다. 반응은 압도적으로 긍정적이었으며, 반대 의견은 제기되지 않았습니다.
하위 호환성
\x 이스케이프의 의미를 바꾸면 기존 코드가 깨질 위험이 분명히 있지만, 아직 비호환 사례는 발견되지 않았습니다. 그 위험은 극히 적은 것으로 여겨집니다.
Tim Peters는 의도적으로 경계 사례를 유발하는 표준 테스트 스위트의 일부를 제외하면, Python CVS 개발 트리에서도, 자신의 컴퓨터에 있는 여러 Python 패키지에서도 뒤에 2자리보다 적거나 많은 16진수 숫자가 따라오는 \xabcdef... 형태의 사례가 전혀 없다는 것을 확인했습니다.
레퍼런스 매뉴얼이 그러한 형태가 올바르지 않다고 암시했으므로(논란의 여지는 있지만!), 2자리보다 적은 사례가 있을 가능성은 낮습니다. 2자리보다 많은 사례가 있다면, Guido는 어차피 그것이 버그였다고 주장할 준비가 되어 있습니다 <0.9 wink>.
Guido는 O’Reilly의 Python 서적들이 이미 Python이 제안된 방식으로 동작한다고 문서화하고 있다고 전했는데, 이는 아마도 그 책들의 Perl 편집 전통 때문일 것입니다(위에서 말했듯이 Perl은 처음부터 제안된 방식(에 매우 가깝게)으로 동작했습니다).
Finn Bock은 현재 JPython이 \x 이스케이프를 어떻게 처리하는지 예측할 수 없다고 보고했습니다. 이 제안은 모든 Python 구현에서 일관되고 쉽게 구현할 수 있는 명확한 의미를 부여합니다.
다른 도구에 미치는 영향
없는 것으로 여겨집니다. 영향을 받을 가능성이 있는 것은 주로 파싱 도구이지만, 작성자가 아는 한 “백슬래시가 있으면 다음 문자를 삼킨다”라는 근사를 넘어서 Python 문자열의 내부 구조까지 신경 쓰는 도구는 없습니다. Tim Peters는 python-mode.el, 표준 tokenize.py와 pyclbr.py, 그리고 IDLE 문법 강조 하위 시스템을 확인했으며, 이들 중 어느 것도 변경할 필요가 없다고 봅니다. tabnanny.py나 checkappend.py 같은 도구는 tokenize.py로부터 면역성을 물려받습니다.
참조 구현
코드 변경이 매우 간단하므로 별도의 패치는 만들지 않습니다. 이 분야의 전문가인 Fredrik Lundh가 코드를 작성하고 있으며, 2.0b1이 릴리스되기 전에 변경 사항을 바로 체크인할 것입니다.
BDFL 선언
네, SyntaxError가 아니라 ValueError입니다. “리터럴 해석의 문제는 전통적으로 문법 오류가 아니라 ‘런타임’ 예외를 발생시킵니다.”
참고 문헌
Copyright
This document has been placed in the public domain.