[Final] PEP 261 - Support for “wide” Unicode characters

원문 링크: PEP 261 - Support for “wide” Unicode characters

상태: Final 유형: Standards Track 작성일: 27-Jun-2001

PEP 261 – “와이드(Wide)” 유니코드 문자 지원

개요 (Abstract)

이 PEP(Python Enhancement Proposal) 261은 Python 2.2에서 “와이드(wide)” 유니코드 문자를 지원하기 위한 제안입니다.

Python 2.1까지의 유니코드 문자는 0부터 2**16 - 1 (0xFFFF)까지의 코드 포인트(ordinal)만 가질 수 있었습니다. 이 범위는 유니코드에서 기본 다국어 평면(Basic Multilingual Plane, BMP)에 해당합니다. 그러나 유니코드에는 이 평면을 넘어선 다른 “평면(planes)”에 존재하는 문자들도 있습니다. 유니코드에서 가장 큰 주소 지정 가능한 문자는 17 * 2**16 - 1 (0x10FFFF)의 코드 포인트를 가지며, 이 문자와 같이 더 큰 범위의 문자를 이 PEP에서는 “와이드 문자(wide characters)”라고 부릅니다.

용어 설명 (Glossary)

  • 문자 (Character): Python 유니코드 문자열의 주소 지정 가능한 단위를 의미합니다.
  • 코드 포인트 (Code point): 0부터 0x10FFFF까지의 정수입니다. 유니코드를 정수에서 문자로의 매핑으로 생각할 때, 각 정수는 코드 포인트입니다. 문자에 매핑되지 않는 정수도 코드 포인트이며, 일부는 미래에 문자로 사용될 수 있고, 일부는 절대 문자로 사용되지 않을 것이 보장됩니다.
  • 코덱 (Codec): 물리적 인코딩(예: 디스크 또는 네트워크에서 오는 데이터)과 논리적인 Python 객체 간의 변환을 위한 함수 집합입니다.
  • 인코딩 (Encoding): 추상적인 문자를 물리적인 비트와 바이트로 표현하는 메커니즘입니다. 인코딩을 통해 유니코드 문자를 디스크에 저장하거나 네트워크를 통해 전송하여 다른 유니코드 소프트웨어와 호환되도록 합니다.
  • 서로게이트 페어 (Surrogate pair): 단일 논리 문자를 나타내는 두 개의 물리적 문자입니다. 32비트 코드 포인트를 두 개의 16비트 코드 포인트로 표현하기 위한 약속의 일부입니다.
  • 유니코드 문자열 (Unicode string): “문자열 의미론(string semantics)”(예: 대소문자 변환, 정규 표현식 호환성 등)을 가진 코드 포인트 시퀀스를 나타내는 Python 타입입니다. unicode() 함수로 생성됩니다.

제안된 해결책 (Proposed Solution)

단순히 최대 코드 포인트를 더 큰 값으로 늘리는 것도 한 가지 해결책이 될 수 있습니다. 그러나 이 아이디어를 구현하는 가장 간단한 방법은 문자당 4바이트를 사용하는 것입니다. 이는 대부분의 유니코드 문자열 크기를 두 배로 늘리는 효과를 가져옵니다. 이러한 비용을 모든 사용자에게 부과하는 것을 피하기 위해, Python 2.2는 빌드 시점에 4바이트 구현을 선택할 수 있는 옵션을 제공할 것입니다. 사용자는 와이드 문자를 지원할지, 아니면 메모리 보존을 선호할지 선택할 수 있습니다.

  • 4바이트 옵션은 “wide Py_UNICODE“라고 불립니다.
  • 2바이트 옵션은 “narrow Py_UNICODE“라고 불립니다.

대부분의 기능은 wide 및 narrow 빌드에서 동일하게 작동합니다.

unichr(i) 함수는 다음과 같이 작동합니다.

  • 0 <= i < 2**16 범위에서는 항상 길이가 1인 문자열을 반환합니다.
  • 2**16 <= i <= TOPCHAR (0x10FFFF) 범위에서는 wide Python 빌드에서 길이가 1인 문자열을 반환합니다. narrow 빌드에서는 ValueError를 발생시킵니다.

논의 사항 (Issues)

  1. \U 리터럴과 서로게이트 페어: Python은 현재 단일 Python 문자로 표현할 수 없는 \U 리터럴을 허용하며, 이는 “서로게이트 페어”로 알려진 두 개의 Python 문자를 생성합니다. 이 동작을 미래의 narrow Python 빌드에서 금지해야 할까요?
    • 찬성 (Pro): 이는 narrow Python 빌드에서도 “와이드 문자”를 구성하는 간단한 방법으로 설계되었습니다. 유니코드 리터럴 구문이 unicode-escape 코덱을 호출하는 짧은 형식임을 고려할 때 논리적이기도 합니다.
    • 반대 (Con): 서로게이트를 쉽게 생성할 수 있지만, 사용자는 여전히 슬라이싱, 인덱싱, 출력 등에 주의해야 합니다. 따라서 일부에서는 유니코드 리터럴이 서로게이트를 지원해서는 안 된다고 제안했습니다.
  2. 유니코드 코드 포인트에 해당하지 않는 문자 구성 허용 여부: Python이 유니코드 코드 포인트에 해당하지 않는 문자를 구성하는 것을 허용해야 할까요? 할당되지 않은 유니코드 코드 포인트는 언제든지 할당될 수 있으므로 허용되어야 합니다. 그러나 0x10FFFF를 초과하는 코드 포인트는 유니코드에서 절대 사용되지 않을 것이 보장됩니다. 그래도 이러한 코드 포인트에 대한 접근을 허용해야 할까요?
    • 찬성 (Pro): Python 사용자가 자신이 무엇을 하는지 안다고 생각한다면, 유니코드 사양을 위반하는 것을 막으려 할 필요가 있을까요? 8비트 문자열에 비-ASCII 문자가 포함되는 것을 막지 않는 것과 마찬가지입니다.
    • 반대 (Con): 코덱 및 기타 유니코드 소비 코드는 유니코드 사양에서 허용되지 않는 이러한 문자에 주의해야 할 것입니다.

ord()는 항상 unichr()의 역함수입니다. 현재 인터프리터의 유니코드 문자열에서 문자 최대 코드 포인트를 설명하는 정수 값이 sys 모듈에 있습니다. sys.maxunicode는 narrow 빌드에서는 2**16-1 (0xFFFF)이고, wide 빌드에서는 0x10FFFF입니다.

  1. TOPCHARunichr 도메인 상한을 위한 별도의 상수 필요 여부: TOPCHARunichr의 실제 도메인 상한(서로 다른 경우)에 접근하기 위한 별도의 상수가 있어야 할까요? sys.unicodewidth라는 상수를 ‘wide’ 또는 ‘narrow’ 값을 가질 수 있도록 제안하기도 했습니다.

모든 Python 유니코드 문자는 정확히 하나의 유니코드 코드 포인트를 나타냅니다(즉, Python 유니코드 문자 = 추상 유니코드 문자). 코덱은 “와이드 문자”를 지원하도록 업그레이드될 것입니다(UCS-4에서는 직접, UTF-8 및 UTF-16에서는 가변 길이 시퀀스로 표현). 이것이 구현에서 남은 주요 부분입니다. 유니코드 세계에는 32비트 코드 포인트를 두 개의 16비트 코드 포인트로 인코딩하는 관례가 있습니다(“서로게이트 페어”라고 알려져 있습니다). Python의 코덱은 이 관례를 채택하고 narrow Python 빌드에서 32비트 코드 포인트를 서로게이트 페어로 인코딩할 것입니다.

  1. 코덱이 서로게이트를 생성하지 않고 와이드 문자를 오류로 처리하도록 지시하는 방법: 코덱이 서로게이트를 생성하지 않고 대신 와이드 문자를 오류로 처리하도록 지시하는 방법이 있어야 할까요?
    • 찬성 (Pro): 고정 너비 문자만으로 작동하고 서로게이트에 대해 걱정할 필요가 없는 코드를 작성하고 싶을 수 있습니다.
    • 반대 (Con): 이를 코덱에 전달하는 방법에 대한 명확한 제안이 없습니다.

“서로게이트를 위해 예약된” 코드 포인트를 부적절하게 사용하는 문자열을 구성하는 데는 제한이 없습니다. 이를 “고립된 서로게이트(isolated surrogates)”라고 합니다. 코덱은 파일에서 이러한 것을 읽는 것을 허용해서는 안 되지만, 문자열 리터럴 또는 unichr()을 사용하여 구성할 수 있습니다.

구현 노트 (Implementation Notes)

새로운 매크로(#define)가 추가되었습니다. #define Py_UNICODE_SIZE 2 UCS-2 또는 UCS-4가 사용 중인지 테스트하려면, UCS-4가 사용 중일 때 정의되는 파생 매크로 Py_UNICODE_WIDE를 사용해야 합니다.

새로운 configure 옵션이 추가되었습니다.

  • --enable-unicode=ucs2: narrow Py_UNICODE를 구성하고, wchar_t가 적합하면 사용합니다.
  • --enable-unicode=ucs4: wide Py_UNICODE를 구성하고, wchar_t가 적합하면 사용합니다.
  • --enable-unicode: --enable-unicode=ucs2와 동일합니다.
  • --disable-unicode: 유니코드 기능을 완전히 제거합니다.

또한, 언젠가 --enable-unicode가 플랫폼의 wchar_t 너비를 기본값으로 사용하게 될 것이 제안되었습니다.

Windows 빌드는 당분간 narrow 빌드로 유지될 것입니다. 이는 와이드 문자에 대한 요청이 거의 없었으며, 이러한 요청은 대부분 자체 Python을 구매할 능력이 있는 하드코어 프로그래머로부터 왔고, Windows 자체도 16비트 문자에 강하게 편향되어 있기 때문입니다.

참고: 이 PEP는 유니코드를 사용하는 사람들이 디스크의 파일이나 네트워크를 통해 전송되는 파일에 4바이트 인코딩을 사용해야 한다는 것을 의미하지 않습니다. 단지 그렇게 할 수 있도록 허용하는 것입니다. 예를 들어, ASCII는 여전히 합법적인 (7비트) 유니코드 인코딩입니다.

narrow Python 빌드에서 프로그래머를 위해 서로게이트를 처리하는 모듈이 있어야 한다고 제안되었습니다. 만약 누군가가 이를 구현하고자 한다면, 그것은 또 다른 PEP가 될 것입니다. 이는 다른 종류의 문자, 단어, 줄 기반 인덱싱을 허용하는 기능과 결합될 수도 있습니다.

거부된 제안 (Rejected Suggestions)

이 섹션에서는 채택되지 않은 다른 해결책들을 설명합니다.

  • 현상 유지 (More or less the status-quo): Python 문자를 16비트로 공식적으로 명시하고, 프로그래머가 서로게이트 페어를 조합하여 애플리케이션 로직에서 와이드 문자를 구현하도록 요구할 수 있었습니다. 이는 Python으로만 코딩될 경우 32비트 문자 에뮬레이션이 매우 비효율적일 가능성이 있어 큰 부담이 됩니다. 또한, 이러한 추상화된 의사(pseudo) 문자열은 정규 표현식 엔진의 입력으로 유효하지 않았을 것입니다.

  • “공간 효율적인 유니코드(Space-efficient Unicode)” 타입: 다른 해결책으로는 내부적으로 효율적인 스토리지를 사용하되, 프로그래머에게는 와이드 문자의 추상화를 제공하는 것이 있었습니다. 이러한 방법들은 채택된 해결책보다 훨씬 더 복잡한 구현을 요구했을 것입니다. 예를 들어, 정규 표현식 엔진에 미치는 영향을 고려해야 합니다. 이론적으로는 Python 코드를 깨뜨리지 않고 미래에 이 구현으로 전환할 수 있습니다. 미래의 Python은 narrow Python에서 wide Python의 의미론을 “에뮬레이트”할 수 있습니다. 그러나 귀도 반 로섬(Guido van Rossum)은 당장 이 구현을 맡을 의사가 없었습니다.

  • 두 가지 타입 (Two types): 16비트 유니코드 타입과 함께 32비트 유니코드 타입을 도입할 수 있었습니다. 그러나 단일 유니코드 타입만 존재할 것으로 예상하는 많은 코드가 있습니다.

이 PEP는 최소한의 노력으로 구현할 수 있는 해결책을 제시합니다. 향후 몇 년 동안 32비트 유니코드 문자가 더욱 보편화될 것이며, 이는 더 정교한 해결책이 필요하다는 확신을 주거나 (반대로) 단순히 와이드 유니코드 문자를 의무화하는 것이 적절한 해결책이라는 확신을 줄 수도 있습니다. 현재 고려할 수 있는 두 가지 옵션은 아무것도 하지 않거나 이 제안을 따르는 것입니다.

⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.

Comments