2

私はいくつかのテストを行っていましたが、 (さまざまな質問/回答でも確認されているように)よりもはるかにxrange()高速であることがわかりました。range()

>>> from timeit import timeit
>>> timeit(stmt = 'x = range(1000)', number = 10000)
0.38216601211680734
>>> timeit(stmt = 'x = xrange(1000)', number = 10000)
0.010537726631953959 # xrange is much faster than range

私は興味を持ったので、別のテストを試して、list(xrange(1000))単によりも高速になるかどうかを確認しましたrange(1000)

>>> timeit(stmt = 'x = range(1000)', number = 10000)
0.3858838963796529
>>> timeit(stmt = 'x = list(xrange(1000))', number = 10000)
0.492734766028903 # now, xrange is slower

これは、より多くの呼び出しにも当てはまります。

>>> timeit(stmt = 'x = range(1000)', number = 100000)
3.6457308233315757
>>> timeit(stmt = 'x = list(xrange(1000))', number = 100000)
5.722031755612818

それで、私の質問は、なぜそれ自体list(xrange)よりも大幅に遅いのですか?range

、およびその他のコンストラクター メソッドの遅さに関するこの質問list()dict()を見たので、なぜlist(xrange)そんなに遅いのでしょうか?

を使用すると、が よりも多くの計算dis.dis()を実行することがわかりました):list(xrange)range

>>> dis.dis('x = list(xrange(1000))')
          0 SETUP_LOOP      15648 (to 15651)
          3 SLICE+2        
          4 IMPORT_NAME     29545 (29545)
          7 LOAD_GLOBAL     30760 (30760)
         10 POP_JUMP_IF_FALSE 28257
         13 BUILD_LIST      10341
         16 <49>           
         17 <48>           
         18 <48>           
         19 <48>           
         20 STORE_SLICE+1  
         21 STORE_SLICE+1  
>>> dis.dis('x = range(1000)')
          0 SETUP_LOOP      15648 (to 15651)
          3 SLICE+2        
          4 POP_JUMP_IF_FALSE 28257
          7 BUILD_LIST      10341
         10 <49>           
         11 <48>           
         12 <48>           
         13 <48>           
         14 STORE_SLICE+1  
4

2 に答える 2

6

もちろんrange()、あなたが望む最終製品が範囲内のすべての数値のリストである場合、rangeそれはすべて1回の関数呼び出しで実行されます。オブジェクトを反復処理するために作成されたオブジェクトのオーバーヘッドがコンストラクターlist(xrange())に負担をかけるのとは対照的に、コンストラクターはそれを消費する必要があります。リストをすぐに構築するのに対し、中間イテレータの消費はありません...どうすればそれを打ち負かすことができますか? 主な違いは、1 回の関数呼び出しと 2 回、そしてそれほど重要ではありませんが、1 回のグローバル ルックアップと 2 回です。list(..)rangeiteratorxrangelist(..)range()

于 2013-04-27T13:27:46.013 に答える
2

range()すぐにリストを作成して返します。そのため、アイテムが多い場合、ビルドが遅くなります。

一方、xrange()値を要求すると値を生成するイテレータのようなオブジェクトを直接返します。ドキュメントから:

xrange(start, stop[, step])
この関数は range() に非常に似ていますが、リストではなくxrangeオブジェクトを返します。これは、対応するリストと同じ値を生成する不透明なシーケンス型であり、実際にはすべてを同時に格納する必要はありません。xrange()overの利点range()は最小限です (xrange()要求されたときに値を作成する必要があるため)メモリが不足しているマシンで非常に大きな範囲が使用されている場合、または範囲のすべての要素が使用されていない場合 (ループが使用されている場合など)を除きます。通常はブレークで終了します)。

したがって、最初の例でxrange()は自然に速くなりますが、2番目の例では遅くなります。なぜなら、range()すでにリストを返しているが(その後は変換されません)、list(xrange())値を生成するだけでなく、作成するためにさらに多くの作業を行う必要があるからです新しいリストと値の格納。

PS これは Python 2 にも当てはまります。代わりに、Python 3 では、range()Python 2- とまったく同じように動作するものだけがありxrange()ます。

于 2013-04-27T13:28:05.003 に答える