[python] Python 3에서 int를 바이트로 변환

파이썬 3 에서이 바이트 객체를 만들려고했습니다.

b'3\r\n'

그래서 나는 명백한 (나를 위해) 시도하고 이상한 행동을 발견했다.

>>> bytes(3) + b'\r\n'
b'\x00\x00\x00\r\n'

분명히:

>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

바이트 변환이 왜 이런 식으로 문서를 읽는지에 대한 포인터를 볼 수 없었습니다. 그러나이 파이썬 문제 format에서 바이트 추가 에 대한 놀라운 메시지를 발견했습니다 ( Python 3 바이트 형식 참조 ).

http://bugs.python.org/issue3982

이것은 bytes (int)와 같은 홀수와 더 잘 상호 작용하지 않습니다.

과:

bytes (int)가 해당 int의 ASCIIfication을 반환하면 훨씬 편리합니다. 그러나 솔직히 말해서이 행동보다 오류가 더 낫습니다. (내가 가진 적이없는이 행동을 원한다면 오히려 “bytes.zeroes (n)”과 같은 클래스 메쏘드가되고 싶다.

이 행동의 출처를 누군가가 설명 할 수 있습니까?



답변

이것이 설계된 방식입니다. 일반적으로 bytes단일 정수 대신 iterable을 호출하기 때문에 의미가 있습니다 .

>>> bytes([3])
b'\x03'

문서는 다음에 대한 문서 문자열뿐만 아니라 이것을 나타 냅니다 bytes.

 >>> help(bytes)
 ...
 bytes(int) -> bytes object of size given by the parameter initialized with null bytes


답변

파이썬 3.2에서 할 수있는 일

>>> (1024).to_bytes(2, byteorder='big')
b'\x04\x00'

https://docs.python.org/3/library/stdtypes.html#int.to_bytes

def int_to_bytes(x: int) -> bytes:
    return x.to_bytes((x.bit_length() + 7) // 8, 'big')

def int_from_bytes(xbytes: bytes) -> int:
    return int.from_bytes(xbytes, 'big')

따라서, x == int_from_bytes(int_to_bytes(x)). 이 인코딩은 부호없는 (음이 아닌) 정수에 대해서만 작동합니다.


답변

구조체의 팩을 사용할 수 있습니다 :

In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'

“>”는 바이트 순서 (빅 엔디안) 이고 “I”는 형식 문자 입니다. 따라서 다른 작업을 수행하려는 경우 구체적으로 지정할 수 있습니다.

In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'

In [13]: struct.pack("B", 1)
Out[13]: '\x01'

이것은 파이썬 2와 파이썬 3 모두에서 동일하게 작동합니다. .

참고 : unpack을 사용 하여 역 연산 (바이트에서 int)을 수행 할 수 있습니다 .


답변

Python 3.5 이상에서는 printf바이트에 대한 % 보간 ( -style 형식)을 도입했습니다 .

>>> b'%d\r\n' % 3
b'3\r\n'

PEP 0461-바이트 및 바이트 배열에 % 서식 추가를 참조하십시오 .

이전 버전에서는 다음 str.encode('ascii')같은 결과를 사용할 수있었습니다 .

>>> s = '%d\r\n' % 3
>>> s.encode('ascii')
b'3\r\n'

참고 : 그것은 생산 하는 것과int.to_bytes 다릅니다 :

>>> n = 3
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big') or b'\0'
b'\x03'
>>> b'3' == b'\x33' != '\x03'
True


답변

설명서는 다음과 같이 말합니다.

bytes(int) -> bytes object of size given by the parameter
              initialized with null bytes

순서 :

b'3\r\n'

문자 ‘3’(십진 51) 문자 ‘\ r'(13) 및 ‘\ n'(10)입니다.

따라서 다음과 같은 방식으로 처리합니다.

>>> bytes([51, 13, 10])
b'3\r\n'

>>> bytes('3', 'utf8') + b'\r\n'
b'3\r\n'

>>> n = 3
>>> bytes(str(n), 'ascii') + b'\r\n'
b'3\r\n'

IPython 1.1.0 및 Python 3.2.3에서 테스트


답변

3의 ASCIIfication은 "\x33"아닙니다 "\x03"!

그것은 파이썬이하는 일 str(3)이지만 바이너리 데이터의 배열로 간주되고 문자열로 남용되지 않아야하기 때문에 바이트에는 완전히 잘못되었습니다.

원하는 것을 얻는 가장 쉬운 방법 bytes((3,))은입니다 bytes([3]).리스트를 초기화하는 것이 훨씬 비싸기 때문에 튜플을 사용할 수있을 때리스트를 사용하지 마십시오. 을 사용하여 더 큰 정수를 변환 할 수 있습니다 int.to_bytes(3, "little").

주어진 길이로 바이트를 초기화하는 것은 의미가 있으며 가장 유용합니다. 종종 주어진 크기의 메모리가 필요한 일부 버퍼 유형을 만드는 데 사용되기 때문입니다. 배열을 초기화하거나 0을 써서 파일을 확장 할 때 종종 이것을 사용합니다.


답변

int(Python2 포함 long)는 bytes다음 함수 를 사용하여 변환 할 수 있습니다 .

import codecs

def int2bytes(i):
    hex_value = '{0:x}'.format(i)
    # make length of hex_value a multiple of two
    hex_value = '0' * (len(hex_value) % 2) + hex_value
    return codecs.decode(hex_value, 'hex_codec')

역변환은 다른 방법으로 수행 할 수 있습니다.

import codecs
import six  # should be installed via 'pip install six'

long = six.integer_types[-1]

def bytes2int(b):
    return long(codecs.encode(b, 'hex_codec'), 16)

두 함수는 Python2와 Python3 모두에서 작동합니다.