0

このサイトのさまざまな質問を調べて、ファイルから4バイト(32ビットの符号なしリトルエンディアン)整数を読み取る3つの実行可能な方法を見つけました。すなわち:

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

最善を尽くしてあなたがより効率的であることを意味すると仮定すると、私は最初の2つのいずれかを言うでしょう。

このマイクロベンチマークからわかるように、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

また、3番目のものはpython2で機能しませんが、1番目と2番目は機能します(したがって、これらもより移植性があります)。

3つ目もそれほど読みやすくはありませんがstruct、最初の2つのバージョンを理解するのは簡単です。

最初の方が少し速いですが、2番目の要素を選択[0]します。これは、最初の要素を使用していることを明確に示している一方で、そのコンマだけでは速く読むかどうかを確認するのは簡単ではないためです。また、速度の違いは実際には最小限であり、Pythonの新しいバージョンと古いバージョンではおそらく変更されるため、速度のためだけに最初のバージョンを使用しても、あまり最適化されないことに注意してください。

アップデート:

なぜsumそんなに遅いのか(そしてもっと...)を説明するために:

Pythonでは、他の整数と同じように整数がオブジェクトであることを考慮に入れてください。したがって、5 + 22つの整数オブジェクトを作成し、__add__メソッドを実行します。したがって、加算には1つの機械命令は必要ありません。

そのため、ビットシフトソリューションははるかに遅く、中間オブジェクトを作成し、いくつかのメソッド呼び出しを実行する必要があります(引数はインタープリターによってパックおよびアンパックされる必要があるため、「コスト」がかかります)。

Cで効率的なものがPythonで効率的であると想定するべきではありません。

CPythonのコードを最適化するための黄金のルール(注:PythonではなくCPython。PyPy、Jythonなどの代替ではなく、公式の実装について話している)は、「Cレベル」で可能な限り多くの計算を行うことです。「Cレベル」とは、Cで記述された内部関数を意味します。

この場合、「C関数」はstruck.unpackであり、を使用したソリューションよりも優れていますsum(注:内部sumには「Cレベル」ループよりも遅い「Pythonレベル」ループがあります)。

他の例はマップです:

#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)アルゴリズムによって、任意の妥当な入力サイズでどのように打ち負かされるかを示す私の答えを見ると参考になると思います[また[送信者の回答]に注意してください。

これが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 に答える