我试图在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)”那样调用。)

谁能给我解释一下这种行为是怎么来的?


当前回答

你可以使用结构体的包:

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)可以通过unpack完成。

其他回答

这就是它的设计方式——这是有意义的,因为通常,你会在一个可迭代对象上调用bytes,而不是单个整数:

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

文档声明了这一点,以及字节的文档字符串:

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

来自bytes docs:

因此,构造函数参数被解释为bytearray()。

然后,从bytearray docs:

可选的source参数可以用几种不同的方式初始化数组: 如果它是一个整数,数组将具有该大小,并将初始化为空字节。

注意,它与2不同。X(其中X >= 6)行为,其中bytes是简单的str:

>>> bytes is str
True

PEP 3112:

2.6的str与3.0的bytes类型有很多不同之处;最值得注意的是,构造函数完全不同。

这种行为源于这样一个事实:在Python版本3之前,bytes只是str的别名。X bytes是bytearray的不可变版本——全新的类型,不向后兼容。

虽然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修复了一个小的低效率。

文件说:

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上测试