programing

Python 3에서 int를 바이트로 변환하는 중

prostudy 2022. 9. 6. 21:22
반응형

Python 3에서 int를 바이트로 변환하는 중

Python 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'

설명서에서 바이트 변환이 이렇게 작동하는 이유를 찾을 수 없습니다.에서 Python을 추가하는 것에 했습니다.format바이트 수(Python 3 바이트 포맷도 참조):

http://bugs.python.org/issue3982

이는 0을 반환하는 바이트(int)와 같은 홀수와의 상호작용을 더욱 저하시킵니다.

또, 다음과 같이 합니다.

바이트(int)가 해당 int의 ASCIIfification을 반환하는 것이 훨씬 편리합니다.솔직히 에러라도 이 동작보다 낫습니다.(이 동작을 원한다면 (전혀 없었던) "bytes"와 같이 호출되는 클래스 메서드가 좋습니다.제로(n).

누가 이 행동이 어디서 왔는지 설명해 줄 수 있나요?

python 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))위의 부호화는 부호 없는(부정수가 아닌) 정수에만 유효하다는 점에 주의해 주십시오.

부호 있는 정수의 경우 비트 길이는 계산하기가 좀 더 까다롭습니다.

def int_to_bytes(number: int) -> bytes:
    return number.to_bytes(length=(8 + (number + (number < 0)).bit_length()) // 8, byteorder='big', signed=True)

def int_from_bytes(binary_data: bytes) -> Optional[int]:
    return int.from_bytes(binary_data, byteorder='big', signed=True)

건데,은 '아까운'이라고 거죠.일반적으로 전화는bytes「 」 「 」 、 「 」 、 「 」

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

문서에는 다음과 같은 내용이 기재되어 있습니다.bytes:

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

구조물의 팩을 사용할 수 있습니다.

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'

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

주의: 역연산(바이트에서 int)은 언팩으로 실행할 수 있습니다.

Python 3.5+에서는 바이트에 % 인터폴레이션(-printfstyle formating)이 도입되었습니다.

>>> 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'

주의: 다음 제품과는 다릅니다.

>>> 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'(10진수 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을 적어 사용하는 경우가 많습니다.

단일 한 방법들의 이 궁금했습니다.[0, 255]그래서 타이밍 테스트를 몇 가지 하기로 했습니다.

아래의 타이밍과 다양한 값과 설정을 시도하면서 관찰한 일반적인 경향에 따라struct.pack가장 빠른 것 같으며, 그 다음입니다.int.to_bytes,bytes및와 함께, " "str.encode이데올로기보다제시된 보다 더 많은 변화가 점에 하십시오.int.to_bytes ★★★★★★★★★★★★★★★★★」bytes 속도 경우가 있습니다만, 「스위치 속도 은 「스위치 속도 랭킹」입니다.struct.pack확실히 가장 빠릅니다.

Windows 의 CPython 3.7 의 결과:

Testing with 63:
bytes_: 100000 loops, best of 5: 3.3 usec per loop
to_bytes: 100000 loops, best of 5: 2.72 usec per loop
struct_pack: 100000 loops, best of 5: 2.32 usec per loop
chr_encode: 50000 loops, best of 5: 3.66 usec per loop

모듈(이름은 ''')int_to_byte.py

"""Functions for converting a single int to a bytes object with that int's value."""

import random
import shlex
import struct
import timeit

def bytes_(i):
    """From Tim Pietzcker's answer:
    https://stackoverflow.com/a/21017834/8117067
    """
    return bytes([i])

def to_bytes(i):
    """From brunsgaard's answer:
    https://stackoverflow.com/a/30375198/8117067
    """
    return i.to_bytes(1, byteorder='big')

def struct_pack(i):
    """From Andy Hayden's answer:
    https://stackoverflow.com/a/26920966/8117067
    """
    return struct.pack('B', i)

# Originally, jfs's answer was considered for testing,
# but the result is not identical to the other methods
# https://stackoverflow.com/a/31761722/8117067

def chr_encode(i):
    """Another method, from Quuxplusone's answer here:
    https://codereview.stackexchange.com/a/210789/140921

    Similar to g10guang's answer:
    https://stackoverflow.com/a/51558790/8117067
    """
    return chr(i).encode('latin1')

converters = [bytes_, to_bytes, struct_pack, chr_encode]

def one_byte_equality_test():
    """Test that results are identical for ints in the range [0, 255]."""
    for i in range(256):
        results = [c(i) for c in converters]
        # Test that all results are equal
        start = results[0]
        if any(start != b for b in results):
            raise ValueError(results)

def timing_tests(value=None):
    """Test each of the functions with a random int."""
    if value is None:
        # random.randint takes more time than int to byte conversion
        # so it can't be a part of the timeit call
        value = random.randint(0, 255)
    print(f'Testing with {value}:')
    for c in converters:
        print(f'{c.__name__}: ', end='')
        # Uses technique borrowed from https://stackoverflow.com/q/19062202/8117067
        timeit.main(args=shlex.split(
            f"-s 'from int_to_byte import {c.__name__}; value = {value}' " +
            f"'{c.__name__}(value)'"
        ))

int)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 모두에서 작동합니다.

brunsgaard의 이전 답변은 효율적인 인코딩이지만 부호 없는 정수에서만 작동합니다.이것은 부호 있는 정수와 부호 없는 정수 모두에 대해 작동하도록 구축되어 있습니다.

def int_to_bytes(i: int, *, signed: bool = False) -> bytes:
    length = ((i + ((i * signed) < 0)).bit_length() + 7 + signed) // 8
    return i.to_bytes(length, byteorder='big', signed=signed)

def bytes_to_int(b: bytes, *, signed: bool = False) -> int:
    return int.from_bytes(b, byteorder='big', signed=signed)

# Test unsigned:
for i in range(1025):
    assert i == bytes_to_int(int_to_bytes(i))

# Test signed:
for i in range(-1024, 1025):
    assert i == bytes_to_int(int_to_bytes(i, signed=True), signed=True)

「」의 ,(i + ((i * signed) < 0)).bit_length() is 、 「 「 」가 「 」가 됩니다.i.bit_length()후자는 -128, -32768 등의 비효율적인 인코딩을 초래하기 때문입니다.


Credit: 경미한 비효율성을 고친 CervEd.

, 좋은 방법은 '이진법 표현하다', '이진법 표현하다', '이진법 표현하다', '이진법 표현을 하다', '이진법 표현하다', '이진법 표현하다', '이진법 표현하다', '이진법 표현하다', '이진법 표현하다', '이진법 표현하다'를하는 것입니다.ctypes.

import ctypes
x = ctypes.c_int(1234)
bytes(x)

없음 및 )을 .c_uint8,c_int8,c_unit16 ... ), ...)

보다 이전 의 Python에서는 Python 3이 때문에 합니다.bytes요.str3.x . Python 3.x 의 . 。bytes입니다.bytearray - 역호환성이 없습니다.

시작 바이트 문서:

따라서 컨스트럭터 인수는 bytearray()로 해석된다.

다음으로 byearray docs에서 다음을 수행합니다.

옵션의 source 파라미터를 사용하여 어레이를 초기화할 수 있습니다.

  • 정수일 경우 어레이는 해당 크기를 가지며 늘바이트로 초기화됩니다.

이는 2.x(여기서 x >= 6) 동작과는 다릅니다.bytes 말하면str:

>>> bytes is str
True

PEP 3112:

2.6 스트링은 3.0의 바이트 유형과 여러 가지 면에서 다릅니다. 특히 컨스트럭터는 완전히 다릅니다.

많은 숫자에 대응하지 않는 대답도 있습니다.

정수를 16진수로 변환한 다음 바이트로 변환합니다.

def int_to_bytes(number):
    hrepr = hex(number).replace('0x', '')
    if len(hrepr) % 2 == 1:
        hrepr = '0' + hrepr
    return bytes.fromhex(hrepr)

결과:

>>> int_to_bytes(2**256 - 1)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

바이트로 변환하기 전에 int를 str로 변환하면 될 것 같아요.그러면 원하는 형식이 생성됩니다.

bytes(str(your_number),'UTF-8') + b'\r\n'

py3.8에서는 효과가 있습니다.

>>> chr(116).encode()
b't'

질문의 대상이 (스트링에 상당하지 않는) 정수 자체를 바이트로 변환하는 방법이라면, 확실한 대답은 다음과 같습니다.

>>> i = 5
>>> i.to_bytes(2, 'big')
b'\x00\x05'
>>> int.from_bytes(i.to_bytes(2, 'big'), byteorder='big')
5

이러한 방법의 상세한 것에 대하여는, 다음의 URL 를 참조해 주세요.

  1. https://docs.python.org/3.8/library/stdtypes.html#int.to_bytes
  2. https://docs.python.org/3.8/library/stdtypes.html#int.from_bytes

언급URL : https://stackoverflow.com/questions/21017698/converting-int-to-bytes-in-python-3

반응형