通过浏览本网站上的各种问题,我发现了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模块,但是任何特定方法的其他优缺点是什么。
答案 0 :(得分:2)
假设 best 你意味着更有效率,我会说前两个中的任何一个。
从这个微观基准可以看出,第三个更糟糕的是:
>>> 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__
方法。
因此,添加不需要一台机器指令。
这就是为什么bitshift解决方案要慢得多,它必须创建中间对象并执行一些方法调用(&#34;成本&#34;,因为参数必须由解释器打包和解包)。
你不应该认为C中有效的东西在python中是有效的。
在CPython中优化代码的黄金法则(注意:CPython不是python。我正在谈论官方实现,而不是像PyPy,Jython等那样的替代方案),是尽可能多的计算&#34; C级&#34;。按&#34; C级&#34;我指的是用C语言编写的函数内部。
在这种情况下,&#34; C功能&#34;是struck.unpack
,这比使用sum
的解决方案更好(注意:在sum
内部有一个&#34; python级别&#34;循环比一个&#34;慢。 C级&#34;循环)。
另一个例子是map:
#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
解决方案相对于列表理解的速度越快)
我认为你看到this我的回答可能是有益的,我会通过O(n logn)算法展示纯蟒蛇O(n)算法如何通过任何合理的输入大小获得节拍&#34; C级&#34;循环[也请注意[senderle&#39; s answer]。
为什么这在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。