7

私は 2.6 の集合理解を試みていましたが、次の 2 つの方法に出くわしました。最初の方法は2番目の方法よりも速いと思いましたが、timeitそうでなければ提案されました。2 番目のメソッドは追加のリストのインスタンス化とそれに続くセットのインスタンス化を行っているにもかかわらず、なぜ 2 番目のメソッドの方が高速なのですか?

方法 1:

In [16]: %timeit set(node[0] for node in pwnodes if node[1].get('pm'))
1000000 loops, best of 3: 568 ns per loop

方法 2:

In [17]: %timeit set([node[0] for node in pwnodes if node[1].get('pm')]) 
1000000 loops, best of 3: 469 ns per loop

どこでpwnodes = [('e1', dict(pm=1, wired=1)), ('e2', dict(pm=1, wired=1))]

4

2 に答える 2

6

リスト内包表記を使用すると、単純に反復が高速になります。

In [23]: from collections import deque

In [24]: %timeit deque((node[0] for node in pwnodes if node[1].get('pm')), maxlen=0)
1000 loops, best of 3: 305 µs per loop

In [25]: %timeit deque([node[0] for node in pwnodes if node[1].get('pm')], maxlen=0)
1000 loops, best of 3: 246 µs per loop

deque反復速度を示すために使用されます。dequemaxlen設定された a0は、イテラブルから取得されたすべての要素を破棄するため、結果を歪めるメモリ割り当ての違いはありません。

これは、Python 2では、リスト内包表記が個別の名前空間を使用しないのに対し、ジェネレータ式は使用するためです (必要に応じて使用する必要があります)。その追加の名前空間には、スタック上の新しいフレームが必要であり、これにはコストがかかります。ジェネレータ式の主な利点は、速度ではなく、メモリ フットプリントが小さいことです。

Python 3 では、リスト内包表記にも別の名前空間があり、リスト内包表記とジェネレーターの反復速度は同等です。また、Python 2 でも最速の内包表記を設定しました。

于 2015-07-07T14:28:06.263 に答える
2

私の推測では、2 つ目はジェネレーターを含み、最初のものは含まないためです。同等のリストがメモリに収まる場合、ジェネレーターは通常、同等のリストよりも遅くなります。

In [4]: timeit for i in [i for i in range(1000)]: pass
10000 loops, best of 3: 47.2 µs per loop

In [5]: timeit for i in (i for i in range(1000)): pass
10000 loops, best of 3: 57.8 µs per loop
于 2015-07-07T14:27:59.570 に答える