Byte array to Int in Python 2.x using Standard Libraries

时间:2018-04-18 17:55:41

标签: python python-3.x python-2.7

I am comfortable in Python 3.x and Bytearray to Decimal conversion using int.from bytes(). Could come up with the below conversion snippet. Is there a way to achieve the same functionality using Python 2 for positive and negative integers.

val = bytearray(b'\x8f\x0f\xfd\x02\xf4\x95s\x00\x00')
a = int.from_bytes(val, byteorder='big', signed=True)

# print(type(a), type(val), val, a)
# <class 'int'> <class 'bytearray'> bytearray(b'\x8f\x0f\xfd\x02\xf4\x95s\x00\x00') -2083330000000000000000

Need to use Python 2.7 standard libraries to convert byte array to Int.

Eg. bytearray(b'\x00')--> Expected Result: 0
bytearray(b'\xef\xbc\xa9\xe5w\xd6\xd0\x00\x00') --> Expected Result: -300000000000000000000
bytearray(b'\x10CV\x1a\x88)0\x00\x00') --> Expected Result: 300000000000000000000

1 个答案:

答案 0 :(得分:4)

Python 2.7中没有内置函数来完成3.2+中的int.from_bytes;这就是为什么首先添加该方法的原因。

如果您不关心处理除big-endian签名的整数以外的任何情况,并且关心可读性而不是性能(因此您可以扩展或自己维护),最简单的解决方案可能是显式循环超过字节。

对于无符号,这很容易:

n = 0
for by in b:
    n = n * 256 + by

但要处理负数,你需要做三件事:

  • 从最高字节取下符号位。由于我们只关心大端,这是0x80上的b[0]位。
  • 这使得一个空的bytearray成为一个特殊情况,所以特别处理它。
  • 最后,如果设置了符号位,则2补充结果。

所以:

def int_from_bytes(b):
    '''Convert big-endian signed integer bytearray to int

    int_from_bytes(b) == int.from_bytes(b, 'big', signed=True)'''
    if not b: # special-case 0 to avoid b[0] raising
        return 0
    n = b[0] & 0x7f # skip sign bit
    for by in b[1:]:
        n = n * 256 + by
    if b[0] & 0x80: # if sign bit is set, 2's complement
        bits = 8*len(b)
        offset = 2**(bits-1)
        return n - offset
    else:
        return n

(这适用于任何可迭代的整数。在Python 3中,它包括bytesbytearray;在Python 2中,它包括bytearray但不包括str。 )

在Python 3中测试输入:

>>> for b in (bytearray(b'\x8f\x0f\xfd\x02\xf4\x95s\x00\x00'),
...           bytearray(b'\x00'),
...           bytearray(b'\xef\xbc\xa9\xe5w\xd6\xd0\x00\x00'),
...           bytearray(b'\x10CV\x1a\x88)0\x00\x00')):
...     print(int.from_bytes(b, 'big', signed=True), int_from_bytes(b))
-2083330000000000000000 -2083330000000000000000
0 0
-300000000000000000000 -300000000000000000000
300000000000000000000 300000000000000000000

在Python 2中:

>>> for b in (bytearray(b'\x8f\x0f\xfd\x02\xf4\x95s\x00\x00'),
...           bytearray(b'\x00'),
...           bytearray(b'\xef\xbc\xa9\xe5w\xd6\xd0\x00\x00'),
...           bytearray(b'\x10CV\x1a\x88)0\x00\x00')):
...     print int_from_bytes(b)
-2083330000000000000000
0
-300000000000000000000
300000000000000000000

如果这是一个瓶颈,那么几乎肯定会有更快的方法。例如,可能通过gmpy2。实际上,即使将字节转换为十六进制字符串并且未完全启动也可能更快,即使它的工作量超过两倍,如果您可以找到将这些主循环从Python移动到C的方法。或者您可以合并调用struct.unpack_from一次调用8个字节的结果,而不是逐个处理每个字节。但是这个版本应该易于理解和维护,并且不需要stdlib以外的任何东西。