5

ドキュメントのレシピセクションは、次のitertoolsテキストで始まります。

拡張ツールは、基盤となるツールセットと同じ高性能を提供します。反復可能オブジェクト全体を一度にメモリに取り込むのではなく、要素を1つずつ処理することで、優れたメモリパフォーマンスが維持されます。一時変数を排除するのに役立つ機能的なスタイルでツールをリンクすることにより、コードの量を少なく抑えます。インタープリターのオーバーヘッドが発生するforループやジェネレーターを使用するよりも、「ベクトル化された」ビルディングブロックを優先することで、高速性が維持されます。

問題は、オーバーヘッドを回避するためにジェネレータをどのように構築する必要があるかということです。このオーバーヘッドがある貧弱な構造のブロックの例をいくつか挙げていただけますか?

この質問に答えるときに、chain(sequence, [obj])オーバーヘッドが上にあるかどうかを正確に言うことができなかったのでchain(sequence, repeat(obj,1))、後者を好むべきかどうかを尋ねることにしました。

4

1 に答える 1

5

ドキュメントテキストは、オーバーヘッドを回避するためにジェネレータを構築する方法についてではありません。例で提供されているコードなど、正しく記述itertoolsされたコードを使用すると、forループとジェネレーターが完全に回避され、イテレーターを使用するためにitertoolsまたは組み込みコレクター(などlist)に任せられることが説明されています。

たとえば、次のtabulate例を見てください。

def tabulate(function, start=0):
    "Return function(0), function(1), ..."
    return imap(function, count(start))

これを書くためのベクトル化されていない方法は次のようになります。

def tabulate(function, start=0):
    i = start
    while True:
        yield function(i)
        i += 1

このバージョンでは、ループと関数呼び出しがPythonで行われるため、「インタープリターのオーバーヘッドが発生します」。

単一の要素のチェーンに関しては、chain(sequence, [obj])固定長のリストの構築が特殊な構文とオペコードを使用してPythonで十分に最適化されているため、(自明に)高速になると考えるのが安全です。同様chain(sequence, (obj,))に、タプルはリストの最適化を共有し、起動するのが小さいため、さらに高速になります。python -m timeitベンチマークではいつものように、推測するよりも測定する方がはるかに優れています。

ドキュメントの引用は、とのいずれかを選択することによって示されるものなど、イテレータの作成の違いとは関係ありませ。イテレータは単一の要素しか生成しないため、消費方法に違いはありません。ドキュメントでは、数百万の要素を生成する可能性のあるイテレータを処理する際のプロセッサとメモリの効率について説明しています。それに比べて、作成戦略はいつでも変更できるため、作成速度が速いイテレーターを選択するのは簡単です。一方、ベクトル化しない明示的なループを使用するようにコードが設計されると、完全に書き直さずに後で変更するのは非常に困難になる可能性があります。repeat(foo, 1)[foo]

于 2012-10-21T22:13:24.157 に答える