您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

将可变大小的字节数组转换为整数/长整数

将可变大小的字节数组转换为整数/长整数

传统上,Python对于“大尾数C布局中的数字”用处不大,而对于C来说则用不了太多。(如果要处理2字节,4字节或8字节的数字,那么struct.unpack答案就是)

但是足够多的人厌倦了没有一种明显的方法可以做到这一点,Python 3.2添加了一种int.from_bytes完全可以实现您想要的方法

int.from_bytes(b, byteorder='big', signed=False)

不幸的是,如果您使用的是旧版本的Python,则没有此功能。那么,您有什么选择?(除了显而易见的一个:更新为3.2,或者更好的是3.4…)

首先,有您的代码。我认为binascii.hexlify它是比esb更好的拼写方式.encode('hex'),因为“ encode”对于字节串(相对于Unicode字符串)的方法似乎总是有些怪异,并且实际上已在Python 3中被淘汰了。但是,否则,似乎可读性强,对我来说很明显。而且它应该非常快- 是的,它必须创建一个中间字符串,但是它正在C中进行所有循环和算术运算(至少在cpython中),这通常比Python快一两个数量级。除非您bytearray太大,以至于分配字符串本身都会很昂贵,否则我在这里不必担心性能

或者,您可以循环执行。但这将更加冗长,至少在cpython中要慢得多。

您可以尝试消除一个隐式循环的显式循环,但是这样做的明显功能reduce,在社区中,这被视为非Python的—当然,这将需要为每个字节调用一个函数

您可以展开循环,也reduce可以将其分解为8个字节的块并进行循环struct.unpack_from,或者通过做一个大的struct.unpack('Q'*len(b)//8 + 'B' * len(b)%8)循环来进行循环,但这会使它的可读性大大降低,并且可能并没有那么快。

您可以使用NumPy…,但是如果您要大于64位或128位,则最终将所有内容都转换为Python对象。

因此,我认为您的答案是最好的选择。

以下是一些将其与最明显的手动转换进行比较的时间:

import binascii
import functools
import numpy as np

def hexint(b):
    return int(binascii.hexlify(b), 16)

def loop1(b):
    def f(x, y): return (x<<8)|y
    return functools.reduce(f, b, 0)

def loop2(b):
    x = 0
    for c in b:
        x <<= 8
        x |= c
    return x

def numpily(b):
    n = np.array(list(b))
    p = 1 << np.arange(len(b)-1, -1, -1, dtype=object)
    return np.sum(n * p)
In [226]: b = bytearray(range(256))

In [227]: %timeit hexint(b)
1000000 loops, best of 3: 1.8 µs per loop

In [228]: %timeit loop1(b)
10000 loops, best of 3: 57.7 µs per loop

In [229]: %timeit loop2(b)
10000 loops, best of 3: 46.4 µs per loop

In [283]: %timeit numpily(b)
10000 loops, best of 3: 88.5 µs per loop

为了在Python 3.4中进行比较:

In [17]: %timeit hexint(b)
1000000 loops, best of 3: 1.69 µs per loop

In [17]: %timeit int.from_bytes(b, byteorder='big', signed=False)
1000000 loops, best of 3: 1.42 µs per loop

因此,您的方法仍然相当快……

其他 2022/1/1 18:35:24 有466人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶