Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 460 – 바이너리 보간 및 포매팅 추가

Author:
Antoine Pitrou <solipsis at pitrou.net>
Status:
Withdrawn
Type:
Standards Track
Created:
06-Jan-2014
Python-Version:
3.5

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 bytes 및 bytearray 객체에 최소한의 포매팅 연산을 추가할 것을 제안합니다. 제안하는 추가 사항은 다음과 같습니다:

  • 퍼센트 포매팅을 위한 bytes % ... 및 bytearray % ...입니다. str 객체의 퍼센트 포매팅과 문법이 유사합니다(단일 객체, 튜플 또는 딕셔너리를 받습니다).
  • str.format()과 문법이 유사한 포매팅을 위한 bytes.format(...) 및 bytearray.format(...)입니다(위치 인자와 키워드 인자를 모두 받습니다).
  • str.format_map(...)과 유사한 API를 위한 bytes.format_map(...) 및 bytearray.format_map(...)입니다. 포매팅 문법과 의미는 bytes.format() 및 bytearray.format()과 같습니다.

근거

Python 2에서는 str % args와 str.format(args)로 바이트 문자열을 포매팅하고 보간할 수 있습니다. 이 기능은 프로토콜이 고정된 인코딩을 사용한다고 알려진 경우에 프로토콜 메시지를 조립하는 데 흔히 사용되어 왔습니다.

Python 3은 일반적으로 텍스트를 유니코드(즉, bytes가 아닌 str 객체)로 저장하고 다루도록 요구합니다. 하지만 어떤 경우에는 bytes 객체를 직접 다루는 것이 합리적입니다. 전형적인 사용 예는 바이너리 네트워크 프로토콜로, 완전한 프로토콜 메시지를 만들기 위해 여러 bytes 객체(일부는 리터럴이고, 일부는 계산된 값)를 보간하고 조립하고 싶을 수 있습니다. 예를 들어, HTTP나 SIP 같은 프로토콜에는 ASCII 이름과, 가변적이거나 때로는 잘 정의되지 않은 인코딩을 사용하는 불투명한 “텍스트” 값으로 이루어진 헤더가 있습니다. 게다가 이러한 헤더 뒤에는 바이너리 본문이 올 수 있는데… 이 본문은 청크로 나뉘고 ASCII 헤더와 트레일러로 장식될 수도 있습니다!

바이너리 데이터를 누적하는 꽤 효율적인 방법들(bytearray 객체, bytes.join 메서드, 심지어 io.BytesIO를 사용하는 방법 등)이 있기는 하지만, 그 어느 것도 %-포매팅이나 {}-포매팅 템플릿과 포매팅 연산으로 만들어지는 코드만큼 읽기 쉽고 직관적인 코드로 이어지지 않습니다.

바이너리 포매팅 기능

지원하는 기능

이 제안에서 bytes와 bytearray에 대한 퍼센트 포매팅은 다음 기능을 지원합니다:

  • 포매팅 인자를 위치뿐 아니라 이름으로도 조회합니다(즉, %s뿐 아니라 %(name)s도 지원합니다).
  • %s는 주어진 값에서 Py_buffer를 얻으려고 시도하고, 실패하면 __bytes__ 호출로 대체합니다. 그 결과로 얻은 바이너리 데이터는 문자열의 해당 위치에 삽입됩니다. 이는 bytes, bytearray, memoryview 객체(그리고 pathlib의 경로 객체 같은 몇 가지 다른 객체)에서 동작할 것으로 예상됩니다.
  • %c는 0에서 255 사이의 정수를 받아, 해당 값의 바이트를 삽입합니다.

bytes와 bytearray에 대한 중괄호 포매팅은 다음 기능을 지원합니다:

  • str.format()이 지원하는 모든 종류의 인자 조회(명시적 위치 조회, 자동 증가 위치 조회, 키워드 조회, 속성 조회 등)
  • 수정자나 레이아웃이 지정되지 않은 경우(예: {}, {0}, {name}) 바이너리 데이터를 삽입합니다. 이는 퍼센트 포매팅의 %s와 같은 의미를 가집니다(위 참조).
  • c 수정자는 0에서 255 사이의 정수를 받아, 해당 값의 바이트를 삽입합니다(위의 %c와 같습니다).

지원하지 않는 기능

(퍼센트 연산자나 str.format() 메서드를 통한) str 객체 포매팅에 있는 그 밖의 모든 기능은 지원하지 않습니다. 이러한 기능은 연산자나 메서드의 수신 객체를 텍스트로 취급한다는 것을 의미하며, 이는 텍스트와 바이트의 분리에 어긋납니다(예를 들어, %d를 형식 코드로 받아들이면 bytes 객체가 실제로는 ASCII 호환 텍스트 문자열이라는 뜻이 됩니다).

이러한 미지원 기능에는 대부분의 타입별 포맷 코드뿐만 아니라 패딩이나 정렬 같은 다양한 레이아웃 지정자도 포함됩니다. 게다가 str 객체는 예를 들어 %s 포맷 코드를 사용하더라도 포매팅 연산의 인자로 허용되지 않습니다.

__format__은 호출되지 않습니다.

비판

  • 개발 비용과 유지 보수 비용입니다.
  • 3.3에서는 ASCII나 latin-1로 인코딩하는 작업이 memcpy만큼 빠릅니다(하지만 여전히 별도의 객체를 생성합니다).
  • Python 3.4 이하 버전을 지원하려는 개발자는 어차피 바이너리 포매팅이 없다는 점을 우회해야 합니다.
  • bytes 문자열을 결합할 때는 bytes.join()이 포매팅보다 일관되게 빠릅니다(XXX 정말 그렇습니까?).
  • 포매팅 함수는 내장 타입에 추가하는 대신 서드파티 모듈로 구현할 수도 있습니다.

다른 제안

새로운 데이터 타입

“네트워크 프로그래밍”에 특화된 새로운 데이터 타입을 만들자는 제안이 있었습니다. 이 PEP의 저자들은 이것이 역효과를 낳는다고 생각합니다. Python 3에는 이미 바이너리 데이터 조작 전용의 주요 타입이 여러 개 있습니다: bytes, bytearray, memoryview, io.BytesIO.

또 다른 타입을 추가하면 사용자에게 더 큰 혼란을 주고, 라이브러리 간 상호 운용성도 더 까다로워집니다(필요한 변환 때문에 최적이 아니게 될 가능성도 있습니다).

게다가 타입이 하나가 아니라 두 개 필요합니다: 하나는 (해싱을 허용하기 위한) 불변 타입이고, 다른 하나는 (네트워크 메시지를 다룰 때 효율적인 누적이 자주 필요하므로) 가변 타입입니다.

결론

이 PEP는 모듈로 연산자와 함께 bytes 객체를 위한 더 확장된 포매팅 언어를 도입하는 PEP 461이 채택됨에 따라 더 이상 쓸모가 없어졌습니다.

참고 문헌