我试图在Python 3中构建这个bytes对象:
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问题中发现了一些关于向字节添加格式的令人惊讶的消息(另见Python 3字节格式化):
http://bugs.python.org/issue3982
这与bytes(int)返回零这样的奇怪情况的交互更加糟糕
and:
如果字节(int)返回该int的ASCIIfication,对我来说会更方便;但说实话,即使是一个错误也比这种行为要好。(如果我想要这种行为——我从来没有——我宁愿它是一个类方法,像“bytes.zero (n)”那样调用。)
谁能给我解释一下这种行为是怎么来的?
虽然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()而不是i.bit_length(),因为后者会导致-128,-32768等低效编码。
归功于:CervEd修复了一个小的低效率。
从python 3.2开始,你可以使用to_bytes:
>>> (1024).to_bytes(2, byteorder='big')
b'\x04\x00'
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)
如果问题是如何将一个整数本身(不是它的字符串等效)转换为字节,我认为健壮的答案是:
>>> i = 5
>>> i.to_bytes(2, 'big')
b'\x00\x05'
>>> int.from_bytes(i.to_bytes(2, 'big'), byteorder='big')
5
更多关于这些方法的信息:
https://docs.python.org/3.8/library/stdtypes.html#int.to_bytes
https://docs.python.org/3.8/library/stdtypes.html#int.from_bytes
文件说:
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上测试