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

Python 개선 제안 한국어 번역

PEP 358 – “bytes” 객체

Author:
Neil Schemenauer <nas at arctrix.com>, Guido van Rossum <guido at python.org>
Status:
Final
Type:
Standards Track
Created:
15-Feb-2006
Python-Version:
2.6, 3.0
Post-History:


Table of Contents

번역·라이선스 안내

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

업데이트

이 PEP는 PEP 3137로 부분적으로 대체되었습니다.

초록

이 PEP는 원시 바이트 시퀀스 유형의 도입을 개괄합니다. bytes 유형을 추가하는 것은 Python 3.0에서 도입될 유니코드 기반 str 객체로 전환하는 한 단계입니다.

이 PEP는 Python 2.6에서 bytes 유형이 어떻게 작동해야 하는지와 Python 3.0에서 어떻게 작동해야 하는지를 설명합니다. (Python 2.6에서는 str과 unicode라는 두 문자열 유형을 사용하는 반면, Python 3.0에서는 이름은 str이지만 의미 체계는 2.6의 unicode 유형과 같은 하나의 문자열 유형만 사용하게 되므로, 때때로 차이가 있습니다.)

동기

Python의 현재 문자열 객체는 여러 용도로 중복 사용됩니다. 문자열 객체는 문자 시퀀스와 바이트 시퀀스를 모두 저장하는 데 사용됩니다. 이러한 용도의 중복 사용은 혼란과 버그를 일으킵니다. 향후 Python 버전에서는 문자열 객체가 문자 데이터를 저장하는 데 사용됩니다. bytes 객체가 바이트 컨테이너의 역할을 수행합니다. 결국 unicode 유형의 이름은 str로 변경되고 기존 str 유형은 제거됩니다.

사양

bytes 객체는 0에서 255 범위에 있는 정수의 변경 가능한 시퀀스를 저장합니다. 문자열 객체와 달리 bytes 객체를 인덱싱하면 정수가 반환됩니다. 정수가 아닌 객체를 요소에 할당하거나 요소와 비교하면 TypeError 예외가 발생합니다. 0에서 255 범위를 벗어난 값을 요소에 할당하면 ValueError 예외가 발생합니다. bytes의 .__len__() 메서드는 시퀀스에 저장된 정수의 개수, 즉 바이트 수를 반환합니다.

bytes 객체의 생성자는 다음 시그니처를 가집니다.:

bytes([initializer[, encoding]])

인수를 제공하지 않으면 요소가 0개인 bytes 객체가 생성되어 반환됩니다. 초기화 인자는 문자열(2.6에서는 str 또는 unicode), 정수의 이터러블 또는 단일 정수일 수 있습니다. 생성자의 의사 코드는 속도가 아니라 명확한 의미 체계에 맞게 최적화되었으며 다음과 같습니다.:

def bytes(initializer=0, encoding=None):
    if isinstance(initializer, int): # In 2.6, int -> (int, long)
        initializer = [0]*initializer
    elif isinstance(initializer, basestring):
        if isinstance(initializer, unicode): # In 3.0, "if True"
            if encoding is None:
                # In 3.0, raise TypeError("explicit encoding required")
                encoding = sys.getdefaultencoding()
            initializer = initializer.encode(encoding)
        initializer = [ord(c) for c in initializer]
    else:
        if encoding is not None:
            raise TypeError("no encoding allowed for this initializer")
        tmp = []
        for c in initializer:
            if not isinstance(c, int):
                raise TypeError("initializer must be iterable of ints")
            if not 0 <= c < 256:
                raise ValueError("initializer element out of range")
            tmp.append(c)
        initializer = tmp
    new = <new bytes object of length len(initializer)>
    for i, c in enumerate(initializer):
        new[i] = c
    return new

.__repr__() 메서드는 바이트 리터럴을 포함하는 새 bytes 객체를 생성하도록 평가할 수 있는 문자열을 반환합니다.:

>>> bytes([10, 20, 30])
b'\n\x14\x1e'

이 객체에는 str 객체의 .decode() 메서드와 동등한 .decode() 메서드가 있습니다. 이 객체에는 [0-9a-fA-F ] 집합의 문자로 이루어진 문자열을 받아 bytes 객체를 반환하는 클래스 메서드 .fromhex()가 있습니다(binascii.unhexlify와 유사합니다). 예를 들면 다음과 같습니다.:

>>> bytes.fromhex('5c5350ff')
b'\\SP\xff'
>>> bytes.fromhex('5c 53 50 ff')
b'\\SP\xff'

이 객체에는 역변환을 수행하는 .hex() 메서드가 있습니다(binascii.hexlify와 유사합니다).:

>> bytes([92, 83, 80, 255]).hex()
'5c5350ff'

bytes 객체에는 리스트 메서드와 유사한 메서드도 있고 str 메서드와 유사한 메서드도 있습니다. 다음은 대략적인 시그니처와 함께 정리한 전체 메서드 목록입니다.:

.__add__(bytes) -> bytes
.__contains__(int | bytes) -> bool
.__delitem__(int | slice) -> None
.__delslice__(int, int) -> None
.__eq__(bytes) -> bool
.__ge__(bytes) -> bool
.__getitem__(int | slice) -> int | bytes
.__getslice__(int, int) -> bytes
.__gt__(bytes) -> bool
.__iadd__(bytes) -> bytes
.__imul__(int) -> bytes
.__iter__() -> iterator
.__le__(bytes) -> bool
.__len__() -> int
.__lt__(bytes) -> bool
.__mul__(int) -> bytes
.__ne__(bytes) -> bool
.__reduce__(...) -> ...
.__reduce_ex__(...) -> ...
.__repr__() -> str
.__reversed__() -> bytes
.__rmul__(int) -> bytes
.__setitem__(int | slice, int | iterable[int]) -> None
.__setslice__(int, int, iterable[int]) -> Bote
.append(int) -> None
.count(int) -> int
.decode(str) -> str | unicode # in 3.0, only str
.endswith(bytes) -> bool
.extend(iterable[int]) -> None
.find(bytes) -> int
.index(bytes | int) -> int
.insert(int, int) -> None
.join(iterable[bytes]) -> bytes
.partition(bytes) -> (bytes, bytes, bytes)
.pop([int]) -> int
.remove(int) -> None
.replace(bytes, bytes) -> bytes
.rindex(bytes | int) -> int
.rpartition(bytes) -> (bytes, bytes, bytes)
.split(bytes) -> list[bytes]
.startswith(bytes) -> bool
.reverse() -> None
.rfind(bytes) -> int
.rindex(bytes | int) -> int
.rsplit(bytes) -> list[bytes]
.translate(bytes, [bytes]) -> bytes

.isupper(), .upper() 및 그와 유사한 메서드가 눈에 띄게 빠져 있다는 점에 주목하십시오. (그러나 아래의 “Open Issues”를 참조하십시오.) 객체가 변경 가능하므로 .__hash__()는 없습니다. .sort() 메서드의 사용 사례는 없습니다.

bytes 타입은 버퍼 인터페이스도 지원하므로, 문자 데이터가 아닌 바이너리 데이터를 읽고 쓸 수 있습니다.

범위 외 문제

  • Python 3k에는 현재와 상당히 다른 I/O 서브시스템이 제공될 예정입니다. 해당 I/O 서브시스템이 어떻게 작동하고 bytes 객체와 상호 작용할지를 결정하는 것은 이 PEP의 범위를 벗어납니다. 그러나 바이너리 I/O는 bytes를 읽고 쓰는 반면, 텍스트 I/O는 문자열을 읽게 될 것으로 예상합니다. bytes 타입은 버퍼 인터페이스를 지원하므로, Python 2.6의 기존 바이너리 I/O 연산은 bytes 객체를 지원합니다.
  • 객체를 바이트 배열로 변환할 수 있도록 .__bytes__()라는 특수 메서드를 언어에 추가하자는 제안이 있었습니다. 이 결정은 범위를 벗어납니다.
  • b"..." 형식의 bytes 리터럴도 제안되었습니다. 이는 PEP 3112에서 다루는 내용입니다.

미해결 문제

  • .decode() 메서드는 중복됩니다. bytes 객체 b도 (2.6에서는) unicode(b, <encoding>)을 호출하거나 (3.0에서는) str(b, <encoding>)을 호출하여 디코딩할 수 있기 때문입니다. encode/decode 메서드가 정말 필요합니까? 어떤 의미에서는 생성자를 사용하는 표기가 더 깔끔합니다.
  • 메서드를 더욱 신중하게 명세해야 합니다.
  • 피클링 및 마샬링 지원을 명세해야 합니다.
  • 그러한 리스트 메서드를 모두 실제로 구현해야 합니까?
  • 필수적인 두 번째 인자를 사용하는 .ljust(), .rjust(), .center()를 지원해야 한다는 근거를 제시할 수 있습니다.
  • 필수 인자를 사용하는 .split()을 지원해야 한다는 근거를 제시할 수 있습니다.
  • ASCII의 문자, 숫자 및 공백 정의를 사용하여 .islower(), .isupper(), .isspace(), .isalpha(), .isalnum(), .isdigit()와 그에 대응하는 변환(.lower() 등)을 지원해야 한다는 근거를 제시할 수도 있습니다. 이를 받아들이면 .ljust(), .rjust(), .center().split()을 지원해야 한다는 근거가 훨씬 강해지며, ASCII 공백 또는 모든 ASCII 공백(.split()의 경우)을 사용하는 기본 인자도 제공해야 합니다.

자주 묻는 질문

Q: Unicode 객체의 encode 메서드가 동일한 작업을 수행하는데 선택적 인코딩 인자를 두는 이유는 무엇입니까?

A: 현재 Python 버전에서 encode 메서드는 str 객체를 반환하며, 코드를 손상하지 않고는 이를 변경할 수 없습니다. bytes(s.encode(...)) 구성은 바이트 시퀀스를 여러 번 복사해야 하므로 비용이 많이 듭니다. 또한 Python은 일반적으로 A 타입의 객체를 B 타입의 객체로 변환하는 두 가지 방법을 제공합니다. A 인스턴스에 자신을 B로 변환하도록 요청하거나, B 타입에 A로부터 새 인스턴스를 생성하도록 요청하는 방법입니다. A와 B가 무엇인지에 따라 두 API 모두 의미가 있습니다. 때로는 결합도 분리를 위해 A가 B를 알 수 없어야 하므로 전자의 방법을 사용해야 하고, 때로는 B가 A를 알 수 없어야 하므로 후자의 방법을 사용해야 합니다.

Q: 초기화 인자가 str인 경우 bytes가 인코딩 인자를 무시하는 이유는 무엇입니까? (이는 2.6에만 적용됩니다.)

A: 그런 경우 인코딩이 가질 수 있는 합리적인 의미는 없습니다. str 객체는 실제로 바이트 배열이며, 자신이 포함하는 문자 데이터의 인코딩에 대해 전혀 알지 못합니다. 프로그래머가 원하는 인코딩을 이미 사용하는 str 객체를 제공했다고 가정해야 합니다. 바이트의 순수한 복사본이 아닌 다른 것이 필요하다면, 먼저 문자열을 디코딩해야 합니다. 예를 들어:

bytes(s.decode(encoding1), encoding2)

Q: 왜 인코딩 인자의 기본값을 ASCII가 아니라 Latin-1(또는 전체 바이트 범위를 포괄하는 다른 인코딩)로 하지 않습니까?

A: Python의 시스템 기본 인코딩은 ASCII입니다. 그 기본값을 사용하는 것이 가장 덜 혼란스러워 보입니다. 또한 Py3k에서는 Latin-1을 기본값으로 사용하는 것이 사용자의 기대와 다를 수 있습니다. 예를 들어, 사용자는 유니코드 인코딩을 선호할 수도 있습니다. 어떤 기본값도 항상 예상대로 작동하지는 않습니다. 적어도 ASCII는 비-ASCII 데이터를 인코딩하려고 하면 시끄럽게 불평합니다.