302

最近Python3を使い始めましたが、問題はありません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を教えてもらえますか、私はそれを見つけることができません。

4

6 に答える 6

188

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機能はそれとは何の関係もありません。(当然のことながら、__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.xrangeは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.xrangeが削除されました。

3.3オブジェクトが2.xオブジェクトrangeの直接の子孫である(2.x関数の子孫ではない)ことのいくつかの証拠があります: 3.3および2.7へのソース。変更履歴も表示できます(ファイル内の任意の場所で文字列「xrange」の最後のインスタンスを置き換えた変更にリンクされていると思います)。xrangerangerangexrange

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

一つには、彼らは多くの新機能を追加しました。もう1つは、マイナーな副作用を伴うあらゆる種類の変更(特に反復内)を行ったことです。また、重要度の低いケースをわずかに悲観的にすることもありますが、さまざまな重要なケースを劇的に最適化するための多くの作業がありました。これをすべて合計すると、rangeできるだけ速く反復するのが少し遅くなったのは驚きではありません。これは、誰も集中するほど重要ではないケースの1つです。このパフォーマンスの違いがコードのホットスポットである実際のユースケースは、誰も持っていない可能性があります。

于 2013-02-22T00:03:10.850 に答える
150

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

Python2とPython3で動作するものが必要な場合は、これを試してください

try:
    xrange
except NameError:
    xrange = range
于 2013-02-22T01:09:29.197 に答える
22

Python 3のrangeタイプは、Python2のタイプと同じように機能し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

Python 3rangeは、少し高速です。

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(20, 60, 10)

于 2013-02-21T23:42:07.870 に答える
2

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

import sys

if sys.version_info >= (3, 0):
    def xrange(*args, **kwargs):
        return iter(range(*args, **kwargs))
于 2016-01-22T15:18:03.857 に答える
1

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

于 2018-04-07T01:52:23.583 に答える
-1

comp:〜$ python Python 2.7.6(デフォルト、2015年6月22日、17:58:13)linux2の[GCC 4.8.2]

>>> import timeit
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)

5.656799077987671

>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)

5.579368829727173

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

21.54827117919922

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

22.014557123184204

timeit number = 1 paramの場合:

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)

0.2245171070098877

>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=1)

0.10750913619995117

comp:〜$ python3 Python 3.4.3(デフォルト、2015年10月14日、20:28:29)Linux上の[GCC 4.8.4]

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

9.113872020003328

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

9.07014398300089

timeit number = 1,2,3,4の場合、paramは迅速かつ直線的に機能します。

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)

0.09329321900440846

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=2)

0.18501482300052885

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=3)

0.2703447980020428

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=4)

0.36209142999723554

したがって、timeit.timeit( "[x for x in range(1000000)if x%4]"、number = 1)のように1つの実行ループサイクルを測定すると、(実際のコードで実際に使用するように)python3は十分に高速に動作するようです。しかし、繰り返されるループでは、python 2 xrange()がpython 3のrange()に対して速度で勝ちます。

于 2015-12-27T10:46:21.857 に答える