簡體   English   中英

使用struct.unpack將字節轉換為整數,而不是Python中的sum

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM