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

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


当前回答

有些答案对大数字不适用。

将整数转换为十六进制表示,然后将其转换为字节:

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'

其他回答

从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)

3的ASCIIfication是“\x33”而不是“\x03”!

这就是python对str(3)所做的,但对字节来说是完全错误的,因为它们应该被认为是二进制数据的数组,而不应该被滥用为字符串。

实现您想要的最简单的方法是bytes((3,)),这比bytes([3])更好,因为初始化列表的代价要高得多,所以当您可以使用元组时,永远不要使用列表。可以使用int转换更大的整数。“小”,to_bytes(3)。

初始化具有给定长度的字节是有意义的,也是最有用的,因为它们通常用于创建某种类型的缓冲区,为此需要分配一定大小的内存。我经常在初始化数组或通过写入零来扩展某个文件时使用这个方法。

如果问题是如何将一个整数本身(不是它的字符串等效)转换为字节,我认为健壮的答案是:

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

int(包括Python2的long)可以使用以下函数转换为字节:

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上工作。

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