[Final] PEP 3127 - Integer Literal Support and Syntax

원문 링크: PEP 3127 - Integer Literal Support and Syntax

상태: Final 유형: Standards Track 작성일: 14-Mar-2007

PEP 3127 – 정수 리터럴 지원 및 구문

이 문서는 Python 3.0에 도입된 정수 리터럴(Integer Literal) 처리 방식의 변경 사항에 대한 Python Enhancement Proposal (PEP) 3127의 번역 및 요약입니다. 이 PEP는 정수 리터럴의 구문과 관련된 혼란을 줄이고 이진수(binary) 지원을 추가하는 것을 목표로 합니다.

초록 (Abstract)

이 PEP는 다양한 기수(radices, bases)에서 정수의 문자열 리터럴 표현 처리 방식을 합리화하기 위해 Python 코어에 대한 변경을 제안합니다. 이러한 변경 사항은 Python 3.0을 대상으로 하지만, 하위 호환 가능한 부분은 Python 2.6에도 추가되어 모든 유효한 Python 3.0 정수 리터럴이 Python 2.6에서도 유효하도록 합니다.

주요 제안 내용은 다음과 같습니다.

  • 8진수(octal) 리터럴은 더 이상 “0” 대신 선행 “0o” 또는 “0O”로 지정되어야 합니다.
  • 이진수(binary) 리터럴은 선행 “0b” 또는 “0B”를 통해 지원됩니다.
  • 문자열 포매팅에서도 이진수 지원이 고려됩니다.

동기 (Motivation)

이 PEP는 두 가지 다른 문제에 의해 동기가 부여되었습니다.

  1. 기본 8진수 표현의 혼란: C-like 언어에 익숙하지 않은 사람들에게 정수의 기본 8진수 표현은 조용히 혼란을 줍니다. 예를 들어, 013은 Python 언어 자체에서 ‘십진수 11’을 의미하며, 대부분의 사람이 013에 할당하는 ‘십진수 13’이라는 의미가 아닙니다. 이로 인해 의도치 않게 잘못된 값을 가진 정수 객체를 생성하기가 매우 쉽습니다.
  2. 이진수 지원 요구: 일부 Python 사용자들이 언어 내에서 이진수 지원에 대한 강한 요구를 가지고 있습니다.

명세 (Specification)

문법 명세 (Grammar specification)

Python 2.6의 경우, 변경되거나 새로 추가될 토큰(token) 정의는 다음과 같습니다.

integer ::= decimalinteger | octinteger | hexinteger | bininteger | oldoctinteger
octinteger ::= "0" ("o" | "O") octdigit+
bininteger ::= "0" ("b" | "B") bindigit+
oldoctinteger ::= "0" octdigit+
bindigit ::= "0" | "1"

Python 3.0의 경우, oldoctinteger는 지원되지 않으며, 리터럴이 선행 “0” 다음에 숫자가 오는 경우 예외가 발생합니다.

두 버전 모두 PyLong_FromString 함수와 문법 변경이 필요하며, grammar.txt 및 참조 매뉴얼의 정수 리터럴 섹션과 같은 문서도 변경되어야 합니다.

int() 명세 (int() specification)

int(s, 0)도 새 문법 정의와 일치하도록 변경됩니다. 이는 문법 변경에 필요한 PyLong_FromString의 변경을 통해 자동으로 이루어져야 합니다. 또한, int()의 문서도 int(s)int(s, 10)과 동일하게 작동하며, int(s, 0) 설명에서 “guess”라는 단어가 제거되어야 함을 설명하도록 변경됩니다.

long() 명세 (long() specification)

Python 2.6의 경우, long() 구현과 문서도 새 문법을 반영하도록 변경되어야 합니다.

토크나이저 예외 처리 (Tokenizer exception handling)

잘못된 토큰에 선행 “0”이 포함된 경우, 예외 오류 메시지는 현재의 “SyntaxError: invalid token”보다 더 유익해야 합니다. 이는 십진수(decimal)는 선행 0을 가질 수 없으며, 8진수는 선행 0 뒤에 “o”가 필요하다는 것을 설명해야 합니다.

int() 예외 처리 (int() exception handling)

int()를 문자열과 함께 호출할 때 발생하는 ValueError는 오류 메시지에 최소한 명시적으로 기수(base)를 포함해야 합니다. 예를 들어:

ValueError: invalid literal for base 8 int(): 09

oct() 함수 (oct() function)

oct() 함수는 8진수 앞에 0o를 출력하도록 업데이트되어야 합니다 (3.0 및 2.6 호환 모드).

출력 포매팅 (Output formatting)

Python 3.0에서 문자열 % 연산자의 o 옵션에 대한 대체 구문은 0 대신 0o를 추가하도록 업데이트되어야 합니다. Python 2.6에서는 대체 8진수 포매팅이 계속해서 0만 추가합니다. Python 2.6과 3.0 모두에서 % 연산자는 이진수 출력을 지원하지 않습니다. 이는 PEP 3101 (str.format)에서 이미 이진수 출력이 지원되며, 이것이 권장되는 문자열 포매팅 방법이기 때문입니다.

2.6에서 3.0으로의 전환 (Transition from 2.6 to 3.0)

2to3 변환기는 모든 8진수 문자열 리터럴에 o를 삽입해야 합니다. Python 2.6의 Py3K 호환 옵션은 oldoctinteger 리터럴을 사용하려는 시도에 예외를 발생시켜야 합니다.

근거 (Rationale)

배경 (Background)

이 문제에 대한 대부분의 논의는 Python-3000 메일링 리스트에서 2007년 3월 14일부터 시작되었습니다. 이는 숫자의 문자열 앞에 “0”을 붙이는 것이 숫자 문자열의 의미를 완전히 바꾼다는 사실에 일반적인 사람이 완전히 혼란스러워할 것이라는 관찰에서 비롯되었습니다.

역사적인 이유로, Python의 정수 문자열 표현은 다양한 기수에서 문자열 포매팅 및 토큰 리터럴에 대해 C 언어에서 많은 부분을 차용했습니다. 사용 사례를 통해 8진수를 지정하는 역사적인 방법이 혼란스러웠으며, 이진수 리터럴에 대한 추가 지원이 필요하다는 것이 밝혀졌습니다.

이 제안서는 다음과 같은 특징과 관련하여 정수의 문자열 표현에 대해 논의합니다.

  • 일반 모듈 컴파일, eval(), int(token, 0)에 사용되는 리터럴 정수 토큰. (int(token)int(token, 2-36)은 이 제안으로 수정되지 않습니다.)
  • Python 2.6에서는 long()int()와 동일하게 처리됩니다.
  • % 문자열 연산자 또는 새로운 PEP 3101 고급 문자열 포매팅 방법을 통한 정수의 문자열 포매팅.

다음과 같은 가정이 있습니다.

  • 모든 기능은 일관성을 위해 동일한 지원 기수 세트를 가져야 합니다.
  • Python 소스 코드 구문과 int(mystring, 0)은 계속해서 동일한 동작을 공유해야 합니다.

오래된 8진수 구문 제거 (Removal of old octal syntax)

이 PEP는 Python 3.0 (및 Python 2.6의 Python 3.0 미리보기 모드)에서 선행 0을 사용하여 8진수를 지정하는 기능이 언어에서 제거될 것을 제안하며, 선행 “0” 바로 뒤에 다른 숫자가 오는 경우 SyntaxError가 발생합니다.

현재 논의 중 eval('010') == 8은 새로운 사용자에게 혼란을 주기 때문에 더 이상 참이 되어서는 안 된다는 점에 거의 만장일치로 동의했습니다. eval('0010') == 10이 참이 되어야 한다는 제안도 있었지만, 이는 다른 컴퓨터 언어에서의 사용 방식과 너무 일관성이 없어서 실수가 발생할 가능성이 높기 때문에 훨씬 더 논쟁의 여지가 있습니다.

C/C++, Java, Perl, JavaScript를 포함한 거의 모든 인기 있는 컴퓨터 언어는 선행 0이 있는 숫자 시퀀스를 8진수로 취급합니다. 그러나 대부분의 비컴퓨터 세계에서는 십진수를 거의 독점적으로 사용합니다. 많은 사람들이 비십진수 기수와 마주했을 때 당황하고 혼란스러워한다는 수많은 증거가 있습니다.

하지만 대부분의 경우, 사람들은 십진수 앞에 불필요한 0을 붙이지 않습니다. 유일한 예외는 숫자 열을 맞추려고 할 때입니다. 그러나 PEP 8은 Python 코드 정렬을 위해 공백을 사용하는 것을 명시적으로 권장하지 않으므로, 동일한 목적으로 선행 0을 사용하는 것에도 같은 주장이 적용될 것이라고 추측할 수 있습니다.

결론적으로, 컴퓨터 사용에 완전히 새로운 사람이 십진수에 선행 0을 사용하는 경우, Python은 세 가지 옵션을 가질 수 있습니다. a. 현재처럼 조용히 잘못된 처리를 합니다. b. 이것이 유효한 구문이 아니라는 것을 즉시 알려줍니다. (예외 메시지가 더 친절해야 하지만, 이는 다른 PEP의 주제입니다.) c. 컴퓨터가 “0”으로 시작하는 여러 자리 십진수 정수를 받아들인다고 계속 생각하게 합니다.

일부 사람들은 (c)가 올바른 답이라고 열정적으로 믿습니다. 그러나 새로운 사용자가 나중에 AJAX 애플리케이션을 작성할 때 문제가 발생할 수 있습니다. 따라서 Python은 새로운 사용자에게 선행 0을 허용하지 않는다는 것을 즉시 설명함으로써 문제를 해결할 수 있습니다 (합리적인 메시지와 함께!).

지원되는 기수 (Supported radices)

이 PEP는 Python 언어에서 지원되는 기수가 2 (이진), 8 (8진), 10 (십진), 16 (16진)이 될 것을 제안합니다.

오래된 8진수 구문이 언어에서 제거되어야 한다는 데 동의하면, 다음 질문은 “8진수로 숫자를 지정하고 표시할 방법이 실제로 필요한가?”입니다. 이 질문은 “언어가 어떤 기수를 지원해야 하는가?”로 이어집니다. int() 생성자는 2에서 36까지의 명시적인 기수 값을 허용하지만, 모든 기수를 지원하자는 아이디어는 빠르게 거부되었고, 실제 지원을 받은 유일한 기수는 십진수, 16진수, 8진수, 그리고 이진수였습니다.

인간은 끊임없이 다른 숫자 기수를 사용합니다. 예를 들어 “오후 12시 30분”은 12, 60, 2와 같은 세 가지 기수로 구성된 양적 정보를 전달합니다. 그러나 비컴퓨터 숫자 정보는 주로 이름(오전, 오후) 또는 십진 표기법을 통해 전달됩니다. 아라비아 숫자 체계가 인간의 인지에 잘 맞는다는 연구 결과도 있습니다.

ENIAC과 같은 초기 현대 컴퓨터조차도 이진수로 작동하는 컴퓨터가 있었음에도 불구하고 십진수로 계산했습니다. “이진화 십진수” (BCD)에서 작동하도록 설계된 명령어를 가진 PC를 포함한 많은 컴퓨터에서 십진수 컴퓨터 작동이 중요했습니다. BCD는 각 십진수에 4비트를 할당하는 표현 방식입니다. BCD는 반올림이 인간이 하는 방식과 정확히 동일하게 발생하므로, 계산 및 저장 효율성 측면에서 이진수가 우수함에도 불구하고 금융과 같은 분야에서 여전히 사용됩니다.

컴퓨터 하드웨어가 효율적인 계산 및 데이터 저장을 위해 일반적으로 이진수를 사용하지 않았다면, 정수의 문자열 표현은 항상 십진수였을 것입니다. 그러나 프로그래머와 하드웨어 엔지니어는 종종 컴퓨터처럼 생각해야 하므로, Python이 인간이 이해할 수 있는 형태로 이진 데이터를 통신할 수 있는 능력을 갖는 것이 중요합니다.

이진 데이터 표기법이 인간이 인지적으로 쉽게 처리할 수 있어야 한다는 요구 사항은 기호당 정수 비트(bits)를 포함해야 하며, 그 외에는 표준 십진 표기법 (위치는 거듭제곱을 나타내고, 더 큰 값은 왼쪽에 있으며, 알파벳에 너무 많은 기호가 없어야 함 등)을 매우 밀접하게 따라야 한다는 것을 의미합니다.

이러한 이진 데이터 표기법에 대한 “최적의 지점”은 아라비아 숫자 알파벳에서 선택된 단일 기호에 가능한 가장 큰 정수 비트 수를 담는 8진수입니다. 사실, PDP8 및 8080/Z80과 같은 일부 컴퓨터 아키텍처는 명령의 비트 필드를 3비트 그룹으로 배열하고 명령어 세트를 설명하기 위해 8진수 표현을 사용하는 방식으로 8진수를 기반으로 정의되었습니다. 오늘날에도 유닉스 파일 권한 마스크(Unix file permission masks)와 같이 필드당 3비트로 구성된 비트 팩(bit-packed) 구조 때문에 8진수는 중요합니다.

그러나 8진수는 더 큰 숫자에 사용될 때 단점이 있습니다. 기호당 비트 수는 정수이지만 그 자체가 2의 거듭제곱이 아닙니다. 이러한 한계(대부분의 컴퓨터의 워드 크기가 2의 거듭제곱이라는 점을 고려할 때)로 인해 16진수가 8진수보다 더 인기를 얻게 되었습니다. 16진수는 십진수보다 60% 더 큰 알파벳을 필요로 함에도 불구하고 각 기호가 4비트를 포함하기 때문입니다.

유닉스 파일 권한 마스크와 같은 일부 숫자는 8진수로 표현될 때 인간이 쉽게 디코딩할 수 있지만, 16진수로는 디코딩하기 어렵습니다. 반면 다른 숫자는 16진수로 인간이 다루기 훨씬 쉽습니다. 불행히도, 16진수나 8진수로 잘 전달되지 않는 이진수도 컴퓨터에 사용됩니다. 이러한 숫자가 매우 유용한 한 가지 예는 하드웨어 레지스터를 읽고 쓸 때입니다.

Python이 이진 정보를 인간에게 전달하는 능력이 소수의 기술 인구에게만 유용하더라도, 바로 그 인구층에 Python 코어 팀의 대부분이 포함되어 있으므로, 이러한 표기법 중 가장 유용성이 낮은 순수 이진수조차도 Python 커뮤니티 내에서 열렬한 지지자가 많고, 강력한 반대자는 거의 없습니다.

지원되는 기수를 위한 구문 (Syntax for supported radices)

이 제안은 8진수의 경우 대문자 또는 소문자 “o”가 포함된 “0o” 접두사를, 이진수의 경우 대문자 또는 소문자 “b”가 포함된 “0b” 접두사를 사용할 것을 제안합니다.

대문자를 지원하지 않는 것에 대한 강력한 지지가 있었지만, 복소수의 ‘j’, 지수의 ‘e’, 원시 문자열(raw string)의 ‘r’ (몇 가지만 예로 들자면)이 이미 대문자를 지원하므로 이는 다른 PEP의 별도 주제입니다.

다양한 기수를 구분하는 구문은 Python-3000 논의에서 많은 주목을 받았습니다. 이 구문에는 다음과 같은 여러 (때로는 상충되는) 요구 사항과 “있으면 좋은 점”이 있습니다.

  • 입력 구문과 출력 (% 문자열 연산자 등) 구문 모두에서 다른 언어 및 이전 버전의 Python과 합리적으로 호환되어야 합니다.
  • 일반적인 관찰자에게 가능한 한 명확해야 합니다.
  • 다른 기수로 포매팅된 정수를 시각적으로 쉽게 구별할 수 있어야 합니다.

제안된 구문에는 16r100 (16진수 256)과 같은 임의의 기수 접두사와 100h 어셈블러 스타일 접미사와 유사한 기수 접미사가 포함되었습니다. 문자 “O”를 8진수에 사용할 수 있는지에 대한 논쟁은 격렬했습니다. 일부 글꼴에서는 대문자 “O”가 숫자 0과 매우 유사하게 보이기 때문입니다. “oCtal”의 두 번째 글자인 “c” 또는 “ocTal”의 “t”, “biNary”의 “n”을 “heXadecimal”의 “x”와 함께 사용하자는 제안도 있었습니다.

% 문자열 연산자의 경우 “o”는 이미 8진수를 나타내는 데 사용되고 있었습니다. 이진수 포매팅은 % 연산자에 추가되지 않습니다. PEP 3101 (고급 문자열 포매팅)이 이미 이진수를 지원하며, % 포매팅은 미래에 사용되지 않을 예정이기 때문입니다.

결론적으로, 대문자 “O”는 숫자 0처럼 보일 수 있고 대문자 “B”는 숫자 8처럼 보일 수 있으므로, 이러한 접두사는 소문자여야 하지만, 원시 문자열의 ‘r’처럼 이는 선호도 또는 스타일 가이드 문제가 될 수 있다고 결정되었습니다.

미해결 과제 (Open Issues)

논의에서는 16진수의 ‘x’, 원시 문자열의 ‘r’, 지수의 ‘e’, 복소수의 ‘j’와 같은 모든 숫자 및 문자열 특수 수정자에 소문자를 사용해야 한다고 제안되었습니다. 이는 별도의 PEP에 대한 문제입니다.

이 PEP는 입력에 대한 대문자 또는 소문자에 대해 입장을 취하지 않으며, 다른 문자에 대한 입력 구문 분석에서 대문자가 제거되지 않는다면, 일관성을 위해 8진수와 이진수에 추가되어야 한다고만 언급합니다. (대소문자 문제에 대한 PEP는 아직 없으므로, 이 가정하에 변경 사항을 문서화합니다.)

출력 포매팅은 다른 이야기일 수 있습니다. 출력 포맷 문자열에서 대소문자 구분을 위한 선례가 이미 충분히 있으며, 이진수 또는 8진수 출력에 대해 대문자 ‘B’ 또는 ‘O’ 문자를 지원하기 위한 % 문자열 연산자의 “대체 형식”에 유효한 사용 사례가 있다는 합의가 필요합니다. 현재 PEP 3101은 이러한 대체 기능을 지원하지 않으며, hex() 함수는 프로그래머가 ‘x’ 문자의 대소문자를 지정하도록 허용하지 않습니다.

Python 3.0에서 0123이 리터럴 십진수로 허용되어야 한다는 강력한 의견이 여전히 있습니다. 이것이 올바른 방향이라면, 추가 PEP에서 쉽게 다룰 수 있습니다. 이 제안은 근거에서 다룬 이유로 0123이 유효한 8진수가 아니도록 하는 첫 번째 단계만 수행합니다.

  • 2to3 변환기에 2.6 호환 변경만 수행하는 옵션이 있거나 있어야 할까요? 이것이 2.6 릴리스 전에 2.6 라이브러리 코드에 실행되어야 할까요?
  • hex()oct()와 일치하는 bin() 함수가 추가되어야 할까요?
  • 고급 문자열 포매팅이 있을 때 hex()가 정말 유용할까요?

참조 (References)

GNU libc manual printf integer format conversions (http://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html) Python string formatting operations (http://docs.python.org/library/stdtypes.html#string-formatting-operations) The Representation of Numbers, Jiajie Zhang and Donald A. Norman (http://acad88.sahs.uth.tmc.edu/research/publications/Number-Representation.pdf) ENIAC page at Wikipedia (http://en.wikipedia.org/wiki/ENIAC) BCD page at Wikipedia (http://en.wikipedia.org/wiki/Binary-coded_decimal)

이 문서는 퍼블릭 도메인에 공개되었습니다.

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

Comments