最近 Python3 を使い始めましたが、問題はありませんxrange
。
簡単な例:
Python2:
from time import time as t def count(): st = t() [x for x in xrange(10000000) if x%4 == 0] et = t() print et-st count()
Python3:
from time import time as t def xrange(x): return iter(range(x)) def count(): st = t() [x for x in xrange(10000000) if x%4 == 0] et = t() print (et-st) count()
結果はそれぞれ次のようになります。
1.53888392448
3.215819835662842
なぜですか? つまり、なぜxrange
削除されたのですか? これは学習に非常に役立つツールです。初心者にとっては、私のように、誰もがかつてはそうだったように。なぜ削除されたのですか? 適切な PEP を教えていただけますか。見つけることができません。
ベストアンサー1
いくつかのパフォーマンス測定は、timeit
を手動で使用するのではなく、 を使用して行いますtime
。
まず、Apple 2.7.2 64 ビット:
In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.05 s per loop
現在、python.org 3.3.0 64 ビット:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.32 s per loop
In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.31 s per loop
In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.33 s per loop
どうやら、 3.xrange
は 2.x よりも少し遅いようですxrange
。そして、OP のxrange
関数はそれとは何の関係もありません。(スロットへの 1 回限りの呼び出しは、__iter__
ループ内で発生する 10000000 回の呼び出しの中では目立たないので、驚くことではありませんが、誰かが可能性としてそれを提起しました。)
しかし、遅くなったのは 30% だけです。OP はなぜ 2 倍も遅くなったのでしょうか? 同じテストを 32 ビット Python で繰り返すと、1.58 対 3.12 になります。つまり、これは 3.x が 32 ビットに悪影響を与える方法で 64 ビット パフォーマンスに最適化されているケースの 1 つではないかと推測します。
しかし、それは本当に重要なのでしょうか? 3.3.0 64 ビット版でもう一度確認してください。
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
したがって、の構築には、list
反復全体よりも 2 倍以上の時間がかかります。
また、「Python 2.6+ よりもはるかに多くのリソースを消費する」という点については、私のテストでは、3.x はrange
2.x とまったく同じサイズのようですxrange
。また、たとえ 10 倍の大きさだったとしても、不要なリストを構築することは、範囲反復処理で実行できるあらゆることよりも 10000000 倍ほど問題が大きくなります。
for
内部の C ループの代わりに明示的なループはどうでしょうかdeque
?
In [87]: def consume(x):
....: for i in x:
....: pass
In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0)
1 loops, best of 3: 1.85 s per loop
for
したがって、ステートメントで浪費される時間は、 を反復する実際の作業で浪費される時間とほぼ同じですrange
。
範囲オブジェクトの反復処理の最適化について心配している場合は、おそらく間違った場所を探していることになります。
一方、xrange
何度同じことを言われても、 が削除された理由を尋ね続けますが、私はもう一度繰り返します。 は削除されませんでした。 に名前が変更されrange
、 2.x がrange
削除されました。
3.3range
オブジェクトが2.xオブジェクトの直接の子孫であるxrange
(2.x関数ではないrange
)という証拠は次のとおりです。3.3range
そして2.7xrange
。変更履歴(ファイル内の任意の場所にある文字列「xrange」の最後のインスタンスを置き換えた変更にリンクされていると思います)。
では、なぜ遅くなるのでしょうか?
そうですね、まず、新機能が多数追加されました。また、あらゆる場所で (特に反復処理内で) 軽微な副作用を伴うあらゆる種類の変更が行われました。また、重要度の低いケースをわずかに悲観的に評価することがあったとしても、さまざまな重要なケースを劇的に最適化するための作業が数多く行われました。これらすべてを合計すると、range
可能な限り高速に反復処理すると、少し遅くなるのは当然のことです。これは、誰も注目するほど気にしない、重要度の低いケースの 1 つです。このパフォーマンスの違いがコードのホットスポットになるような実際の使用例は、おそらく誰も経験しないでしょう。