在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 bytes
是bytearray
的不可变版本 – 全新的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。