0

通过查看本网站上的各种问题,我发现了 3 种从文件中读取 4 字节(32 位无符号小端序)整数的可行方法。即:

1) myInt, = struct.unpack('<I', bytes)
2) myInt = struct.unpack('<I', bytes)[0]
3) myInt = sum(bytes[i] << (i*8) for i in range(4))

这些中哪个最好?我知道使用 unpack 需要导入 struct 模块,但任何特定方法的其他优点或缺点是什么。

4

1 回答 1

3

最好假设您的意思是更高效,我会说前两个中的任何一个。

正如您从这个微型基准测试中看到的那样,第三个要糟糕得多:

>>> bytes=b'\x10\x11\x12\x13'
>>> import struct
>>> import timeit
>>> timeit.timeit('a,=struct.unpack("<I", bytes)', 'from __main__ import struct, bytes')
0.16049504280090332
>>> timeit.timeit('a=struct.unpack("<I", bytes)[0]', 'from __main__ import struct, bytes')
0.1881420612335205
>>> timeit.timeit('sum(bytes[i] << (i*8) for i in range(4))', 'from __main__ import bytes')
1.2574431896209717

第三个在 python2 中也不起作用,而第一个和第二个可以(所以它们也更便携)。

第三个也不那么可读,虽然struct对前两个版本有一点了解很容易理解。

即使第一个稍微快一点,我还是会选择第二个,因为仅用逗号很难看出阅读速度是否快,同时[0]清楚地表明您正在使用第一个元素。另请注意,速度上的差异确实很小,并且可能会在新/旧版本的 python 中发生变化,因此仅仅为了速度而使用第一个不会有太大的优化。

更新:

解释为什么sum这么慢(还有更多......):

考虑到在 python 中整数是对象,就像任何其他对象一样。因此,当5 + 2您创建两个整数对象并执行该__add__方法时。所以加法不需要一条机器指令。

这就是为什么位移解决方案要慢得多,它必须创建中间对象并执行一些方法调用(这“成本”,因为参数必须由解释器打包和解包)。

你不应该假设在 C 中有效的在 python 中是有效的。

在 CPython 中优化代码的黄金法则(注意:CPython 不是 python。我说的是官方实现,而不是 PyPy、Jython 等替代方案),是在“C 级别”进行尽可能多的计算。“C 级别”是指用 C 编写的内部函数。

在这种情况下,“C 函数”是struck.unpack,它比使用的解决方案更好sum(注意:内部sum有一个“python 级别”循环,它比“C 级别”循环慢)。

另一个例子是地图:

#python2
>>> import timeit
>>> L = ['1', '2', '3'] * 5
>>> timeit.timeit('map(int, L)', 'from __main__ import L')
5.549130916595459
>>> timeit.timeit('[int(x) for x in L]', 'from __main__ import L')
6.402460098266602

(这里的列表越长,map解决方案就列表理解而言越快)

我认为看到我的这个答案可能对您很有启发性,我在其中展示了纯 Python O(n) 算法如何通过使用“C 级”循环的 O(n logn) 算法对任何合理的输入大小进行击败 [also注意 [senderle 的回答]。

为什么这在 python2 中不起作用:

giacomo@jack-laptop:~$ python2
Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> bytes='\x10\x11\x12\x13'
>>> import timeit
>>> timeit.timeit('sum(bytes[i] << (i*8) for i in range(4))', 'from __main__ import bytes')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/timeit.py", line 230, in timeit
    return Timer(stmt, setup, timer).timeit(number)
  File "/usr/lib/python2.7/timeit.py", line 195, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
  File "<timeit-src>", line 6, in <genexpr>
TypeError: unsupported operand type(s) for <<: 'str' and 'int'

在 python2 文件中返回字符串和字符串元素是字符串,所以你不能做移位操作。如果它对您有用,那么您使用的是 python3。

于 2012-10-17T12:57:42.287 回答