当前位置: 首页 > 面试题库 >

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

吴刚毅
2023-03-14
问题内容

如何将(大字节序)可变大小的二进制字节数组转换为(无符号)整数/长整数?例如,'\x11\x34'代表4404

现在,我正在使用

def bytes_to_int(bytes):
  return int(bytes.encode('hex'), 16)

它虽然很小,但有点可读,但可能效率不高。有没有更好(更明显)的方法?


问题答案:

传统上,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(html" target="_blank">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

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



 类似资料:
  • 问题内容: 我有一个接收a的函数,但是我所拥有的a是进行此转换的最佳方法是什么? 我想我可以走很长一段路,然后将其放入字符串并放入字节中,但这听起来很难看,而且我认为还有更好的方法可以做到。 问题答案: 我同意Brainstorm的方法:假设您要传递机器友好的二进制表示形式,请使用该库。OP建议可能会有一些开销。纵观源的实施,我看到它做了一些运行时的决策最大的灵活性。 对?Write()接受一个非

  • 问题内容: 将转换为的快速方法是什么? 例如 问题答案: 看看ByteBuffer类。 设置字节顺序保证了,,和。 或者,你可以手动执行以下操作: 该班是专为尽管这样的脏手任务。实际上,私有定义了以下辅助方法:

  • 问题内容: 我正在使用以下方式读取文件: 我在这里发现。可以转换为吗?将转换为会占用更多空间吗? 编辑:我的文件包含数百万个整数,例如, 100000000 200000000 .....(使用普通的int文件写入)。我读到字节缓冲区。现在,我想将其包装到IntBuffer数组中。怎么做 ?我不想将每个字节转换为int。 问题答案: 您已经在注释中说过,您希望输入数组中的四个字节对应于输出数组中的

  • 问题内容: 我想执行转换而不求助于某些依赖于实现的技巧。有小费吗? 问题答案: 您需要知道字节的字节序。 假设(例如@ WhiteFang34),其是一个长度为4的,然后… … 大端: 小端:

  • 问题内容: 因此基本上,用户是从扫描仪输入中输入序列。 等等。 它可以是任意长度,并且必须是整数。 我想将输入的字符串转换为整数数组。 所以会,就等 有什么提示和想法吗?我正在考虑实现获取先前的编号并将它们解析在一起,并将其应用于数组中的当前可用插槽。但是我不太确定如何编写代码。 问题答案: 您可以从扫描仪中读取整个输入行,然后将其分开,然后得到一个,将每个数字解析为与索引一对一匹配的…(假设输入

  • 问题内容: 我正在尝试将固定大小的数组转换为可变大小的数组(切片): 但是编译器抛出错误: 我应该如何转换? 问题答案: 使用让您在阵列上切片。另请参阅此博客文章,以获取有关数组和切片的更多信息。