4

itertoolsモジュールのドキュメントでこのコメントを見つけました

def dotproduct(vec1, vec2):
    return sum(imap(operator.mul, vec1, vec2))

上記のレシピの多くは、グローバルルックアップをデフォルト値として定義されたローカル変数に置き換えることで最適化できることに注意してください。たとえば、内積レシピは次のように記述できます。

def dotproduct(vec1, vec2, sum=sum, imap=imap, mul=operator.mul):
    return sum(imap(mul, vec1, vec2))

どうですか?。
実用的な顕著なスピードアップはありますか(より大きな関数シグネチャの不便さのバランスをとることができます)?
示されているようなケースでのローカル変数の使用は、どの特定の条件に関連しますか?

編集: timeitでテストしましたが、関連する違いがあります。
vec1、vec2としての2つの40アイテムリストの場合:

グローバルルックアップ->3.22720959404
ローカルルックアップ->3.19884065683

つまり、約 1%のゲイン。

4

1 に答える 1

2

実用的な顕著なスピードアップはありますか(より大きな関数シグネチャの不便さのバランスをとることができます)?

ルックアップは元の定義で1回ずつ行われるため、私はそれを非常に疑っています。関数の意味を変更したことに注意してください。

示されているようなケースでのローカル変数の使用は、どの特定の条件に関連しますか?

タイトなループの内側のみ。この場合、dot_productたとえば非常に大きな行列の乗算で使用される場合(イテレータはもちろん、純粋なPythonでは実行できません)。

編集:私はちょうど両方の関数を分解しました、そして私の要点はまだ立っていますが、私の予感は間違っていました:

>>> def dotproduct(vec1, vec2):
...     return sum(imap(operator.mul, vec1, vec2))
...
>>> dis.dis(dotproduct)
  2           0 LOAD_GLOBAL              0 (sum)
              3 LOAD_GLOBAL              1 (imap)
              6 LOAD_GLOBAL              2 (operator)
              9 LOAD_ATTR                3 (mul)
             12 LOAD_FAST                0 (vec1)
             15 LOAD_FAST                1 (vec2)
             18 CALL_FUNCTION            3
             21 CALL_FUNCTION            1
             24 RETURN_VALUE
>>> def dotproduct(vec1, vec2, sum=sum, imap=imap, mul=operator.mul):
...     return sum(imap(mul, vec1, vec2))
...
>>> dis.dis(dotproduct)
  2           0 LOAD_FAST                2 (sum)
              3 LOAD_FAST                3 (imap)
              6 LOAD_FAST                4 (mul)
              9 LOAD_FAST                0 (vec1)
             12 LOAD_FAST                1 (vec2)
             15 CALL_FUNCTION            3
             18 CALL_FUNCTION            1
             21 RETURN_VALUE
于 2011-07-17T16:38:24.300 に答える