web-dev-qa-db-ja.com

Python3にxrange関数がないのはなぜですか?

最近私はPython 3を使い始めました、そしてそれはxrangeの傷害の欠如です。

簡単な例:

1) 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()

2) 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) 1.53888392448 2) 3.215819835662842

何故ですか? xrangeが削除されたのはなぜですか。それは学ぶのにとても素晴らしいツールです。初心者にとっては、私自身と同じように、私たち全員がある時点にいたように。なぜそれを削除しますか?誰かが私に適切なPEPを教えてもらえますか、私はそれを見つけることができません。

乾杯。

240
catalesia

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.x rangeは実際には2.x xrangeより少し遅いです。そして、OPのxrange関数は、それとは何の関係もありません。 (驚くべきことではありませんが、__iter__スロットへの1回限りの呼び出しは、ループ内で発生するすべての呼び出しに対する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.3 rangeオブジェクトが2.x xrangeオブジェクトの直接の子孫である(そして2.x range関数ではない)ことのいくつかの証拠: .3 range および 2.7 xrangeへのソース変更履歴 (ファイル内の任意の場所にある文字列 "xrange"の最後のインスタンスを置き換える変更にリンクされていると信じています)も見ることができます。

それで、なぜ遅いのですか?

まあ、1つには、多くの新機能が追加されています。別の方法として、彼らはあらゆる面で(特に繰り返しの内部で)軽微な副作用のあるすべての種類の変更を行いました。また、重要度の低いケースをわずかに悲観する場合もありますが、さまざまな重要なケースを劇的に最適化するための多くの作業がありました。これをすべて合計すると、rangeを可能な限り高速に反復するのが少し遅くなったのは驚くことではありません。誰も焦点を当てるほど気にしないという、それほど重要ではないケースの1つです。このパフォーマンスの違いがコードのホットスポットであるような実際のユースケースを持っている人はいないでしょう。

167
abarnert

Python3の範囲Python2のxrangeです。その周りにiterをラップする必要はありません。 Python3で実際のリストを取得するには、list(range(...))を使う必要があります。

Python 2とPython 3で動作するものが欲しいなら、これを試してください。

try:
    xrange
except NameError:
    xrange = range
132
John La Rooy

Python 3のrange型はPython 2のxrangeと同じように動作します。 xrange関数によって返される反復子は、rangeを直接反復処理した場合に得られるものとまったく同じなので、なぜ減速が見られるのかわかりません。

私は自分のシステムの減速を再現することができません。これが私がテストした方法です:

Python 2、xrange

Python 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import timeit
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)
18.631936646865853

rangeを使ったPython 3は少し速いです。

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import timeit
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
17.31399508687869

私は最近Python 3のrange型がスライスのサポートのような他の素晴らしい機能を持っていることを知りました:range(10,100,2)[5:25:5]range(15, 60, 10)です!

15
Blckknght

Python2コードを修正する1つの方法は次のとおりです。

import sys

if sys.version_info >= (3, 0):
    def xrange(*args, **kwargs):
        return iter(range(*args, **kwargs))
1
andrew pate

python 2のxrangeはジェネレータであり、iteratorを実装していますが、rangeは単なる関数です。 Python 3では、なぜxrangeが削除されたのかわかりません。

0