如何将字节字符串转换为整数?

171

如何在Python中将字节字符串转换为整数?

比如这样:'y\xcc\xa6\xbb'

我想出了一个聪明/愚蠢的方法:

sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))

我知道标准库中一定有内置的方法可以更简单地做到这一点......

这与将十六进制数字字符串转换为整数的操作不同,对于前者,您可以使用int(xxx,16),但我想要将实际字节值的字符串转换为整数。

更新:

我有点喜欢James的答案,因为它不需要导入其他模块,但Greg的方法更快:

>>> from timeit import Timer
>>> Timer('struct.unpack("<L", "y\xcc\xa6\xbb")[0]', 'import struct').timeit()
0.36242198944091797
>>> Timer("int('y\xcc\xa6\xbb'.encode('hex'), 16)").timeit()
1.1432669162750244

我用的笨拙方式:

>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943

进一步更新:

有人在评论中问导入另一个模块的问题。好吧,导入模块并不一定是廉价的,请看:

>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371

将导入模块的成本计算在内几乎抵消了该方法的所有优势。我认为这只会包括整个基准运行中导入一次的费用;看看当我每次强制重新加载它时会发生什么:

>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794

毋庸置疑,如果您对这个方法进行了大量的执行,并且仅有一个导入,则此问题在成比例上变得不那么重要。这也可能是I/O成本而非CPU成本,因此可能取决于特定机器的容量和负载特性。


从标准库中导入东西为什么不好? - user3850
andyway,重复的内容:https://dev59.com/KnVD5IYBdhLWcg3wWaVh - user3850
28
你的“进一步更新”有些奇怪...为什么要这么频繁地导入模块? - user3850
5
我知道这是一个老问题。但如果你想让其他人了解最新情况,机械蜗牛的答案(int.from_bytes)在我的电脑上比struct.unpack表现更好。我认为它更易读。 - magu_
13个回答

1
在Python 3中,您可以通过以下方式轻松将字节字符串转换为整数列表(0..255):
>>> list(b'y\xcc\xa6\xbb')
[121, 204, 166, 187]

0

对于较新版本的Python,一种简单的方法是:

int(b'hello world'.hex(), 16)

0
一个使用array.array的相当快速的方法,我已经使用了一段时间:
预定义变量:
offset = 0
size = 4
big = True # endian
arr = array('B')
arr.fromstring("\x00\x00\xff\x00") # 5 bytes (encoding issues) [0, 0, 195, 191, 0]

转换为整数:(读取)

val = 0
for v in arr[offset:offset+size][::pow(-1,not big)]: val = (val<<8)|v

从整数类型:(写入)

val = 16384
arr[offset:offset+size] = \
    array('B',((val>>(i<<3))&255 for i in range(size)))[::pow(-1,not big)]

虽然这些可能会更快。

编辑:
对于一些数字,这里有一个性能测试(Anaconda 2.3.0),显示与reduce()相比读取的稳定平均值:

========================= byte array to int.py =========================
5000 iterations; threshold of min + 5000ns:
______________________________________code___|_______min______|_______max______|_______avg______|_efficiency
⣿⠀⠀⠀⠀⡇⢀⡀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⡀⠀⢰⠀⠀⠀⢰⠀⠀⠀⢸⠀⠀⢀⡇⠀⢀⠀⠀⠀⠀⢠⠀⠀⠀⠀⢰⠀⠀⠀⢸⡀⠀⠀⠀⢸⠀⡇⠀⠀⢠⠀⢰⠀⢸⠀
⣿⣦⣴⣰⣦⣿⣾⣧⣤⣷⣦⣤⣶⣾⣿⣦⣼⣶⣷⣶⣸⣴⣤⣀⣾⣾⣄⣤⣾⡆⣾⣿⣿⣶⣾⣾⣶⣿⣤⣾⣤⣤⣴⣼⣾⣼⣴⣤⣼⣷⣆⣴⣴⣿⣾⣷⣧⣶⣼⣴⣿⣶⣿⣶
    val = 0 \nfor v in arr: val = (val<<8)|v |     5373.848ns |   850009.965ns |     ~8649.64ns |  62.128%
⡇⠀⠀⢀⠀⠀⠀⡇⠀⡇⠀⠀⣠⠀⣿⠀⠀⠀⠀⡀⠀⠀⡆⠀⡆⢰⠀⠀⡆⠀⡄⠀⠀⠀⢠⢀⣼⠀⠀⡇⣠⣸⣤⡇⠀⡆⢸⠀⠀⠀⠀⢠⠀⢠⣿⠀⠀⢠⠀⠀⢸⢠⠀⡀
⣧⣶⣶⣾⣶⣷⣴⣿⣾⡇⣤⣶⣿⣸⣿⣶⣶⣶⣶⣧⣷⣼⣷⣷⣷⣿⣦⣴⣧⣄⣷⣠⣷⣶⣾⣸⣿⣶⣶⣷⣿⣿⣿⣷⣧⣷⣼⣦⣶⣾⣿⣾⣼⣿⣿⣶⣶⣼⣦⣼⣾⣿⣶⣷
                  val = reduce( shift, arr ) |     6489.921ns |  5094212.014ns |   ~12040.269ns |  53.902%

这是一个原始的性能测试,因此端序 pow-flip 被省略了。
所示的 shift 函数应用与 for 循环相同的移位或操作,arr 只是 array.array('B',[0,0,255,0]),因为它具有比 dict 更快的迭代性能。

我还应该注意到,效率是通过平均时间的准确性来衡量的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接