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'(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"
!
That is what python does for str(3)
but it would be totally wrong for bytes, as they should be considered arrays of binary data and not be abused as strings.
The most easy way to achieve what you want is bytes((3,))
, which is better than bytes([3])
because initializing a list is much more expensive, so never use lists when you can use tuples. You can convert bigger integers by using int.to_bytes(3, "little")
.
Initializing bytes with a given length makes sense and is the most useful, as they are often used to create some type of buffer for which you need some memory of given size allocated. I often use this when initializing arrays or expanding some file by writing zeros to it.
int
(including Python2's long
) can be converted to bytes
using following function:
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')
The reverse conversion can be done by another one:
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)
Both functions work on both Python2 and Python3.
The behaviour comes from the fact that in Python prior to version 3 bytes
was just an alias for str
. In Python3.x bytes
is an immutable version of bytearray
- completely new type, not backwards compatible.
From bytes docs:
Accordingly, constructor arguments are interpreted as for bytearray().
Then, from bytearray docs:
The optional source parameter can be used to initialize the array in a few different ways:
- If it is an integer, the array will have that size and will be initialized with null bytes.
Note, that differs from 2.x (where x >= 6) behavior, where bytes
is simply str
:
>>> bytes is str
True
The 2.6 str differs from 3.0’s bytes type in various ways; most notably, the constructor is completely different.
I was curious about performance of various methods for a single int in the range [0, 255]
, so I decided to do some timing tests.
Based on the timings below, and from the general trend I observed from trying many different values and configurations, struct.pack
seems to be the fastest, followed by int.to_bytes
, bytes
, and with str.encode
(unsurprisingly) being the slowest. Note that the results show some more variation than is represented, and int.to_bytes
and bytes
sometimes switched speed ranking during testing, but struct.pack
is clearly the fastest.
Results in CPython 3.7 on Windows:
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
Test module (named 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)'"
))
Although the prior answer by brunsgaard is an efficient encoding, it works only for unsigned integers. This one builds upon it to work for both signed and unsigned integers.
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)
For the encoder, (i + ((i * signed) < 0)).bit_length()
is used instead of just i.bit_length()
because the latter leads to an inefficient encoding of -128, -32768, etc.
Credit: CervEd for fixing a minor inefficiency.
If you don't care about the performance, you can convert an int to str first.
number = 1024
str(number).encode()
참고URL : https://stackoverflow.com/questions/21017698/converting-int-to-bytes-in-python-3
'IT' 카테고리의 다른 글
Homebrew를 사용하여 Mac에 Python 2와 3을 모두 설치하려면 어떻게해야합니까? (0) | 2020.06.25 |
---|---|
주어진 문자열이 Java에서 유효한 JSON인지 확인하는 방법 (0) | 2020.06.25 |
부트 스트랩 경고 자동 닫기 (0) | 2020.06.25 |
래퍼 "https"를 찾을 수 없습니다. PHP를 구성 할 때 랩퍼를 활성화하는 것을 잊었습니까? (0) | 2020.06.25 |
받아쓰기하는 파이썬 튜플 (0) | 2020.06.25 |