3

重複の可能性:
Python に結果のないマップはありますか?

プログラムで、イテラブルに含まれる各アイテムに対してインプレース メソッドを迅速かつ効率的に呼び出したい場合がよくあります。(簡単に言うと、for ループのオーバーヘッドは受け入れられません)。draw()良い例は、各Spriteオブジェクトを呼び出したい場合のスプライトのリストです。

私はこのようなことができることを知っています:

[sprite.draw() for sprite in sprite_list]

しかし、返されたリストを使用していないため、リスト内包表記が誤用されているように感じます。機能についても同様mapです。時期尚早の最適化のために私を石で打ちますが、戻り値のオーバーヘッドも望んでいません。

私が知りたいのは、おそらく以下に提案する仮想関数のように、今説明したことを実行できるメソッドが Python にあるかどうかです。

do_all(sprite_list, draw)

4

2 に答える 2

10

いつでも独自のdo_all関数を作成できます。

def do_all(iterable, func):
    for i in iter(iterable):
       func(i)

その後、いつでも呼び出すことができます。

for明示的なループを使用しても、実際にはパフォーマンスの問題はありません。

リスト内包表記 または を使用するとパフォーマンスの問題が発生します、これmapは結果のリストを作成する場合に限られます。明らかに、途中で 5 億個のリストを作成する必要がある場合、5 億個以上のアイテムを繰り返すのは非常に遅くなります。

スプライトのリストの描画などでは、これがほぼ確実に発生しないことをここで指摘しておく価値があります。描画する 500M のスプライトがありません。その場合、None の 5 億個のコピーのリストを作成するよりも、おそらくはるかに長い時間がかかるでしょう。そして、500M のオブジェクトに対して同じ非常に単純なことを行う必要があるもっともらしいケースでは、 に切り替えるなどのより良い解決策がありますnumpy。しかし、これが発生する可能性があるいくつかの考えられるケースがあります。

これを回避する簡単な方法は、ジェネレーター式 or itertools.imap(または、Python 3 では単にmap) を使用し、関数を記述して値を破棄するdisposeことです。1 つの可能性:

def dispose(iterator):
    for i in iterator:
        pass

それで:

dispose(itertools.imap(Sprite.draw, sprite_list))

次のように定義することもできますdo_all

def do_all(iterable, func):
    dispose(itertools.imap(func, iterable))

明確さや単純さのためにこれを行っている場合、それは見当違いだと思います。for ループのバージョンは完全に読みやすく、このバージョンは、間違った関数名と構文で Haskell を記述しようとしているように見えます。

もしあなたがパフォーマンスのためにそれをやっているのなら…まあ、これが問題となる実際のパフォーマンス状況があったとしたら (それはあまりありそうにないようです)、おそらく、さまざまな潜在的な の実装で遊んでみたくなるでしょうdispose。余分な関数呼び出しを避けるために、おそらく を にdispose戻しdo_all、C ですべてを実装することもできます (stdlib の itertools.c から高速反復コードを借用します)。

または、より良いのはpip install more-itertools、 を使用することmore_itertools.consumeです。価値のあることとしては、現在のバージョンはcollections.deque(iterator, maxlen=0). C. しかし、誰かが実装した場合、または将来の Python (または PyPy) がそれを実装するためのより高速な方法を提供する場合、more-itertoolsそれを見つけてコードを変更する前に追加される可能性があります。

于 2012-12-08T00:40:22.257 に答える
7

sprite_list が Sprite オブジェクトのリストであると仮定すると、次のことができます。

map(Sprite.draw, sprite_list)

sprite_listこれにより、投稿したリスト内包表記と本質的に同じである各アイテムで Sprite.draw() が呼び出されます。リストを作成したくない場合は、for ループを使用できます。

for sprite in sprite_list:
    sprite.draw()
于 2012-12-08T00:36:59.567 に答える