在Python 3中将int转换为字节

我试图在Python 3中构build这个字节对象:

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

这与现在返回零的字节(int)之类的奇怪相互作用甚至更差

和:

如果bytes(int)返回了那个int的ASCII值,那对我来说会更方便; 但说实话,即使一个错误会比这个行为更好。 (如果我想要这种行为 – 我从来没有 – 我宁愿它是一个类方法,调用像“bytes.zeroes(n)”。)

有人能解释我这个行为的来源吗?

这就是它被devise的方式 – 这是有道理的,因为通常,你会调用一个迭代而不是一个整数的bytes

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

文档说明了这一点 ,以及bytes的文档string:

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

从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): return x.to_bytes((x.bit_length() + 7) // 8, 'big') def int_from_bytes(xbytes): 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' 

“>”是字节顺序(big-endian) ,“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)可以通过解包来完成。

该文件说:

 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' 

testingIPython 1.1.0和Python 3.2.3

Python 3.5+为字节引入了%-interpolation( printf样式格式) :

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

3的ASCII码是"\x33"而不是"\x03"

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

实现你想要的最简单的方法是bytes((3,)) ,这比bytes([3])更好,因为初始化列表要贵得多,因此在使用元组时不要使用列表。 你可以使用int.to_bytes(3, "little")来转换更大的整数。

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

这种行为来自于这样一个事实:在版本3之前的Python中, bytes只是str的别名。 在Python3.x bytesbytearray的不可变版本 – 全新的types,不向后兼容。

从字节文档 :

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

然后,从bytearray文档 :

可选的source参数可以用几种不同的方式初始化数组:

  • 如果它是一个整数,则数组将具有该大小,并将用空字节进行初始化。

注意,这与2.x(其中x> = 6)行为不同,其中bytes简单地是str

 >>> bytes is str True 

PEP 3112 :

2.6的str与3.0的字节types不同, 最值得注意的是,构造函数是完全不同的。

int (包括Python2的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。