7

Windows で Python 3.3.1 64 ビットを使用しており、次のコード スニペットを使用しています。

len ([None for n in range (1, 1000000) if n%3 == 1])

これと比較して、136ミリ秒で実行されます。

sum (1 for n in range (1, 1000000) if n%3 == 1)

これは 146 ミリ秒で実行されます。この場合、ジェネレーター式はリスト内包表記よりも高速または同じ速度であるべきではありませんか?

Guido van Rossum From List Comprehensions to Generator Expressions から引用します。

... Python 3 のリスト内包表記とジェネレーター式の両方が、実際には Python 2 よりも高速です! (そして、2 つの間に速度の違いはなくなりました。)

編集:

で時間を計測しましたtimeit。あまり正確ではないことはわかっていますが、ここでは相対速度のみを気にし、さまざまな反復回数でテストすると、リスト内包バージョンの時間が一貫して短くなります。

4

2 に答える 2

7

ここでの違いは、完全に 1000000 追加のコストにあると思います。Mac OS X での 64 ビット Python.org 3.3.0 でのテスト:

In [698]: %timeit len ([None for n in range (1, 1000000) if n%3 == 1])
10 loops, best of 3: 127 ms per loop
In [699]: %timeit sum (1 for n in range (1, 1000000) if n%3 == 1)
10 loops, best of 3: 138 ms per loop
In [700]: %timeit sum ([1 for n in range (1, 1000000) if n%3 == 1])
10 loops, best of 3: 139 ms per loop

したがって、理解が genexp よりも速いというわけではありません。どちらもほぼ同じ時間がかかります。lenしかし、a の呼び出しlistは瞬時に行われますが、100 万の数字を合計すると、合計時間がさらに 7% 増えます。

いくつかの異なる数値を投げると、リストが非常に小さい場合 (その場合高速になるように思われる)、またはメモリ割り当てが重要な要素になり始めるほど大きい場合 (まだそうではない) でない限り、これは持ちこたえるようです。 、333K)。

于 2013-04-30T19:26:14.197 に答える
0

この回答から借用すると、考慮すべきことが2つあります。

1. Python リストはインデックス可能であり、その長さをフェッチするのに O(1) 回しかかかりません。これはlen()、リストの呼び出し速度がそのサイズに依存しないことを意味します。ただし、ジェネレーターを呼び出すlen()と、ジェネレーターが生成するすべてのアイテムを消費するため、時間の計算量は O(n) になります。

2.上記のリンクされた回答を参照してください。リスト内包表記は C のタイトなループですが、ジェネレーターは反復子への参照を内部に格納し、next(iter)生成するすべてのアイテムを呼び出す必要があります。これにより、ジェネレーターのオーバーヘッドの別のレイヤーが作成されます。小規模では、リスト内包表記とジェネレーターのパフォーマンスの違いは無視しても問題ありませんが、大規模ではこれを考慮する必要があります。

于 2018-09-03T05:06:19.973 に答える