[英]Converting bytes to integer using struct.unpack versus sum in Python
通過查看本網站上的各種問題,我發現了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模塊,但是任何特定方法的其他優缺點是什么。
假設最好的意思是更有效率,我會說前兩個中的任何一個。
從這個微觀基准可以看出,第三個更糟糕:
>>> 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解決方案要慢得多,它必須創建中間對象並執行一些方法調用(“成本”,因為參數必須由解釋器打包和解包)。
你不應該認為C中有效的東西在python中是有效的。
在CPython中優化代碼的一條黃金法則(注意:CPython不是python。我正在談論官方實現,而不是PyPy,Jython等替代方案),是在“C級別”盡可能多地進行計算。 “C級”是指用C語言編寫的內部函數。
在這種情況下,“C函數”是struck.unpack
,這比使用sum
的解決方案更好(注意:內部sum
有一個“python級別”循環,它比“C級”循環慢)。
另一個例子是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
解決方案相對於列表理解就越快)
我認為你可以看到我的這個答案是有益的,我在這里展示了純蟒蛇O(n)算法如何通過使用“C級”循環的O(n logn)算法獲得任何合理輸入大小的優勢[也注意[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文件中,返回字符串和字符串元素是字符串,因此您無法執行shift操作。 如果它適合你,那么你使用的是python3。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.