Python 2.Xのrange関数とxrange関数の違いは何ですか?


719

どうやらxrangeの方が速いですが、なぜそれが速いのか(そして、これまでのところ、逸話的なものの方が速いという証拠がない)か、それ以外に何が違うのかはわかりません

for i in range(0, 20):
for i in xrange(0, 20):

回答:


817

Python 2.xの場合:

  • rangeリストを作成するので、これを行うrange(1, 10000000)と、9999999要素を含むメモリ内にリストが作成されます。

  • xrange 遅延評価されるシーケンスオブジェクトです。

Python 3では、Python rangeのと同等のものをxrange実行しますlist(range(...))。リストを取得するには、を使用する必要があります。


65
xrangeはまさにntoジェネレーターですが、遅延評価され、ジェネレーターのように機能します。
Vaibhav Mishra 2012

47
xrange(x).__iter__()ジェネレーターです。
augustomen

34
なぜ範囲を遅延させるのではなく、xrangeを作成したのですか?
Rob Grant、

22
@RobertGrant、彼らはしました。Python 3で(すべての変更は下位互換性がある必要があるため、Python 2.x行ではそれを行うことができませんでした。)
Paul Draper

12
@Ratulは、それぞれiが初期化ではなくオンデマンドで評価されることを意味します。
Onilol 2015

223

rangeはリストを作成するので、これを行うrange(1, 10000000)と、9999999要素を含むリストがメモリ内に作成されます。

xrange はジェネレーターであるため、遅延評価されるシーケンスオブジェクトです

これは事実ですが、Python 3では.range()Python 2によって実装され.xrange()ます。実際にリストを生成する必要がある場合は、次のことを行う必要があります。

list(range(1,100))

3
範囲が「for i in range(
1、10

10
+1この回答をありがとう、Python 3でrangeをxrangeに置き換えることに関する情報は非常に役立ちます。私は実際に誰かにxrangeまたはrangeを使用するように言いました、そして彼らはそれがpython 3では問題ではないと言ったので、私は詳細をグーグル検索し、この答えが浮上しました:)
Cervo

xrangeジェネレーターを呼び出すことの何が問題になっていますか?これはyieldステートメントを含む関数であり、用語集によれば、このような関数はジェネレータと呼ばれます。
-Winterlight、

@winterlight、正しい用語はイテレータだと思います。ジェネレーターも受信できる必要があります。
McSinyx

112

timeitモジュールを使用して、コードの小さなスニペットのどれが速いかをテストしてください!

$ python -m timeit 'for i in range(1000000):' ' pass'
10 loops, best of 3: 90.5 msec per loop
$ python -m timeit 'for i in xrange(1000000):' ' pass'
10 loops, best of 3: 51.1 msec per loop

個人的には、本当に大量のリスト.range()を扱っているのでない限り、私は常にを使用します-ご覧のとおり、100万のエントリのリストの場合、追加のオーバーヘッドはわずか0.04秒です。そして、Coreyが指摘しているように、Python 3.0 は廃止され、とにかく素晴らしいイテレータ動作を提供します。.xrange().range()


12
timeitの例では+1。注:Windows cmdで実行するには、二重引用符を使用する必要があります。つまり、 "です。したがって、コードは次のようになりますpython -m timeit "for i in xrange(1000000):" " pass"
stalk

10
xrangeの主な利点は、時間ではなくメモリです。
内部石、2014

3
実用的な答えを1: 使用は巨大な場合を除き及びます。ところでそれらは概念的には同じですよね?奇妙なことに、答えはありません。
ボブスタイン

6
xrangeが高速でメモリを消費しない場合、なぜrangeを使用するのですか?
オースティンモール

8
私はあなたの声明に概ね同意しますが、あなたの評価は間違っています。the extra overhead is only 0.04 secondsそれを見る正しい方法ではありません。(90.5-51.1)/51.1 = 1.771 times slowerこれがプログラムのコアループである場合、それがボトルネックになる可能性があることを伝えるためです。ただし、これが小さな部分である場合、1.77xはそれほど多くありません。
chacham15 2014

65

xrange範囲パラメータのみを保存し、オンデマンドで数値を生成します。ただし、PythonのC実装は現在、その引数をC longに制限しています。

xrange(2**32-1, 2**32+1)  # When long is 32 bits, OverflowError: Python int too large to convert to C long
range(2**32-1, 2**32+1)   # OK --> [4294967295L, 4294967296L]

Python 3.0 rangeでは、2.xと同じように動作xrangeしますが、最小エンドポイントと最大エンドポイントの制限はありません。


39

xrangeはイテレータを返し、一度に1つの数値のみをメモリに保持します。rangeは、数値のリスト全体をメモリに保持します。


9
xrangeイテレータを返しませ
abarnert 2015年

and only keeps one number in memory at a time残りが配置される場所と私を導いてください...
SIslam

5
@SIslam開始、終了、および現在がわかっている場合、一度に1つずつ計算できます。
Justin Meiners 2017年

30

Library Referenceを少し時間をかけてください。それに慣れれば読むほど、このような質問に対する回答をすばやく見つけることができます。特に重要なのは、組み込みオブジェクトと型に関する最初のいくつかの章です。

xrangeタイプの利点は、xrangeオブジェクトは、それが表す範囲のサイズに関係なく、常に同じ量のメモリを使用することです。一貫したパフォーマンス上の利点はありません。

Pythonコンストラクトに関する簡単な情報を見つけるもう1つの方法は、docstringとhelp-functionです。

print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)

1
ライブラリは良いですが、あなたが持っている質問への答えを得ることは必ずしもそれほど簡単ではありません。
Teifion 2008

2
ライブラリリファレンスに移動し、ctrl + fを押して範囲を検索すると、2つの結果が得られます。この質問に対する答えを見つけることはそれほど努力ではありません。
デビッドロック

1
ライブラリ参照が機能していません。更新して頂けますか?
mk ..

14

私は誰もドキュメントを読んでいないことにショックを受けています:

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


13

rangeはリストを作成するため、range(1、10000000)を実行すると、メモリ内に10000000要素のリストが作成されます。xrangeはジェネレーターであるため、遅延評価されます。

これには2つの利点があります。

  1. を取得せずに、より長いリストを繰り返すことができますMemoryError
  2. 各数値を遅延して解決するため、反復を早期に停止しても、リスト全体を作成する時間を無駄にすることはありません。

12

あなたはの利点でしょうxrangeオーバーをrangeこの単純な例では:

import timeit

t1 = timeit.default_timer()
a = 0
for i in xrange(1, 100000000):
    pass
t2 = timeit.default_timer()

print "time taken: ", (t2-t1)  # 4.49153590202 seconds

t1 = timeit.default_timer()
a = 0
for i in range(1, 100000000):
    pass
t2 = timeit.default_timer()

print "time taken: ", (t2-t1)  # 7.04547905922 seconds

上記の例は、の場合、大幅に優れたものを反映していませんxrange

次にrange、と比較して本当に遅い次のケースを見てくださいxrange

import timeit

t1 = timeit.default_timer()
a = 0
for i in xrange(1, 100000000):
    if i == 10000:
        break
t2 = timeit.default_timer()

print "time taken: ", (t2-t1)  # 0.000764846801758 seconds

t1 = timeit.default_timer()
a = 0
for i in range(1, 100000000):
    if i == 10000:
        break
t2 = timeit.default_timer() 

print "time taken: ", (t2-t1)  # 2.78506207466 seconds

を使用するとrange、0〜100000000(時間がかかる)のリストが既に作成されていますxrangeが、ジェネレーターであり、必要に基づいて、つまり反復が継続する場合にのみ数値を生成します。

Python-3では、range機能の実装はxrangePython-2 と同じですがxrange、Python-3では廃止されています。

ハッピーコーディング!!


11

最適化のためです。

range()は、開始から終了までの値のリストを作成します(例では0 .. 20)。これは、非常に大きな範囲ではコストのかかる操作になります。

一方、xrange()はより最適化されています。(xrangeシーケンスオブジェクトを介して)必要な場合にのみ次の値を計算し、range()のようにすべての値のリストを作成しません。


9

range(x,y)forループを使用する場合、xとyの間の各数値のリストを返しますが、range速度は遅くなります。実際、rangeインデックスの範囲が大きくなっています。range(x.y)xとyの間のすべての数値のリストを出力します

xrange(x,y)戻りますxrange(x,y)が、forループを使用した場合xrangeは高速です。xrangeインデックスの範囲が狭くなっています。xrange印刷するxrange(x,y)だけでなく、そこにあるすべての数値を保持します。

[In] range(1,10)
[Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
[In] xrange(1,10)
[Out] xrange(1,10)

forループを使用すると、うまくいくでしょう

[In] for i in range(1,10):
        print i
[Out] 1
      2
      3
      4
      5
      6
      7
      8
      9
[In] for i in xrange(1,10):
         print i
[Out] 1
      2
      3
      4
      5
      6
      7
      8
      9

ループを使用してもそれほど大きな違いはありませんが、印刷するだけでは違いがあります。


8

range(): range(1、10)は、1〜10個の数値のリストを返し、リスト全体をメモリに保持します。

xrange(): range()と同様ですが、リストを返す代わりに、要求に応じて範囲内の数値を生成するオブジェクトを返します。ループの場合、これはrange()よりもわずかに高速で、メモリ効率が向上します。イテレータのようなxrange()オブジェクトで、オンデマンドで数値を生成します(遅延評価)

In [1]: range(1,10)

Out[1]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [2]: xrange(10)

Out[2]: xrange(10)

In [3]: print xrange.__doc__

xrange([start,] stop[, step]) -> xrange object

6

他の回答の一部は、Python 3は2.xの者を排除することを言及するrangeと2.xのと改名xrangeしますrange。ただし、3.0または3.1(だれもがそうであるべきではない)を使用している場合を除き、実際には多少異なる型です。

3.1ドキュメントは言います:

範囲オブジェクトの動作はほとんどありませんlen。インデックスオブジェクト、反復、および関数のみをサポートします。

ただし、3.2以降でrangeは、は完全なシーケンスです。これは、拡張スライスと、とcollections.abc.Sequence同じセマンティクスを持つすべてのメソッドをサポートしlistます。*

そして、少なくともCPythonとPyPy(現在存在する2つ以上の3.2+実装)では、indexand countメソッドとin演算子の定数時間実装も(整数のみを渡す限り)あります。これは、執筆123456 in rが3.2+以降では妥当であることを意味しますが、2.7または3.1では恐ろしい考えになります。


* 2.6-2.7および3.0-3.1 でissubclass(xrange, collections.Sequence)戻るという事実True 3.2で修正されたバグであり、バックポートされていません。


6

Python 2.xの場合

range(x)は、メモリ内にx要素で作成されるリストを返します。

>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]

xrange(x)は、オンデマンドで数値を生成するジェネレータobjであるxrangeオブジェクトを返します。これらはforループ(遅延評価)中に計算されます。

ループの場合、これはrange()よりわずかに高速で、メモリ効率が向上します。

>>> b = xrange(5)
>>> b
xrange(5)

xrange()ジェネレータではありません。xrange(n).__ iter __() `です。
th3an0maly

5

ループでxrangeに対して範囲をテストするとき(私はtimeitを使用する必要があることを知っていますが、これは単純なリスト内包例を使用してメモリからすばやくハッキングされました)、次のことがわかりました。

import time

for x in range(1, 10):

    t = time.time()
    [v*10 for v in range(1, 10000)]
    print "range:  %.4f" % ((time.time()-t)*100)

    t = time.time()
    [v*10 for v in xrange(1, 10000)]
    print "xrange: %.4f" % ((time.time()-t)*100)

それは与える:

$python range_tests.py
range:  0.4273
xrange: 0.3733
range:  0.3881
xrange: 0.3507
range:  0.3712
xrange: 0.3565
range:  0.4031
xrange: 0.3558
range:  0.3714
xrange: 0.3520
range:  0.3834
xrange: 0.3546
range:  0.3717
xrange: 0.3511
range:  0.3745
xrange: 0.3523
range:  0.3858
xrange: 0.3997 <- garbage collection?

または、forループでxrangeを使用します。

range:  0.4172
xrange: 0.3701
range:  0.3840
xrange: 0.3547
range:  0.3830
xrange: 0.3862 <- garbage collection?
range:  0.4019
xrange: 0.3532
range:  0.3738
xrange: 0.3726
range:  0.3762
xrange: 0.3533
range:  0.3710
xrange: 0.3509
range:  0.3738
xrange: 0.3512
range:  0.3703
xrange: 0.3509

スニペットは適切にテストされていますか?xrangeの遅いインスタンスに関するコメントはありますか?またはより良い例:-)


2
このようなベンチマークを1回実行しても、正確なタイミング結果は得られません。常に差異があります。GCか、CPUを盗む別のプロセスのいずれかである可能性があります。そのため、ベンチマークは通常10-100-1000 -...
Vajk Hermeczの

これは急いでスニペットを印刷したものです-私は数回実行しましたが、最大で約100で、xrange少し高速に見えましたが、Python 3では比較が冗長になりました。
Dave Everitt

3
これがtimeit目的です。これは、最高の時計代わりに使用して、GCを無効にすることを、何度も実行しているの世話をするtimeなど、
abarnert

4

pythonのxrange()とrange()はユーザーの場合と同様に機能しますが、両方の関数を使用してメモリがどのように割り当てられるかを話しているときに違いが生じます。

range()を使用する場合は、生成するすべての変数にメモリを割り当てます。そのため、より大きなnoでの使用は推奨されません。生成される変数の。

一方、xrange()は一度に特定の値のみを生成し、必要なすべての値を出力するためにforループでのみ使用できます。


3

rangeはリスト全体を生成し、それを返します。xrangeは行いません-要求に応じてリストの数値を生成します。


2

xrangeはイテレータを使用し(その場で値を生成します)、rangeはリストを返します。


2

何?
range実行時に静的リストを返します。
xrangeを返しますobject必要なときのように、そこからの値が生成される(それは確かではないですが、発電機のように機能します)。

いつ使用するのですか?

  • 使用する xrange特に携帯電話のような「メモリに敏感なシステム」を持っているときに、10億と言った巨大な範囲のリストを生成したい場合にます。
  • rangeリストを数回繰り返したい場合に使用します。

PS:Python 3.xのrange関数== Python 2.xのxrange関数。


xrangeジェネレータオブジェクトを返しません。
abarnert 2015年

私が正しく理解しているなら、それがここで説明されている方法です(Python 2.xの場合):wiki.python.org/moin/Generators
kmario23

次に、wikiは間違っています。(「SH」が誰で、そのコメントを追加して署名したかはわかりません。)公式ドキュメントは正しいです。自分でテストして、ジェネレータかシーケンスかを確認できます。
abarnert 2015年

OK。しかし、それはまだこれを読んだ後混乱だ:stackoverflow.com/questions/135041/...
kmario23

1
面白い質問は、通訳が公式ドキュメントまたは別の通訳に同意しない場合にどうするかです...しかし、幸いにも、あまり頻繁に出てくることはありません…
abarnert

2

誰もがそれを大きく説明しました。しかし、私はそれを自分の目で見てほしかった。私はpython3を使用しています。そこで、Windowsでリソースモニターを開き、最初に次のコマンドを最初に実行しました。

a=0
for i in range(1,100000):
    a=a+i

次に、「使用中」のメモリの変更を確認しました。ささいなことでした。次に、次のコードを実行しました。

for i in list(range(1,100000)):
    a=a+i

そして、それはすぐに使用するためにメモリの大きなチャンクを必要としました。そして、私は確信しました。自分で試すことができます。

Python 2Xを使用している場合は、最初のコードで「range()」を「xrange()」に、「list(range())」を「range()」に置き換えます。


2

ヘルプドキュメントから。

Python 2.7.12

>>> print range.__doc__
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers

Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!
These are exactly the valid indices for a list of 4 elements.

>>> print xrange.__doc__
xrange(stop) -> xrange object
xrange(start, stop[, step]) -> xrange object

Like range(), but instead of returning a list, returns an object that
generates the numbers in the range on demand.  For looping, this is 
slightly faster than range() and more memory efficient.

Python 3.5.2

>>> print(range.__doc__)
range(stop) -> range object
range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).

>>> print(xrange.__doc__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'xrange' is not defined

違いは明らかです。Python 2.xでは、rangeリストをxrange返し、反復可能なxrangeオブジェクトを返します。

Pythonの3.xのでは、rangeとなっxrangeたPython 2.xのの、およびxrange削除されます。


1

0-Nアイテムのスキャン/印刷の要件では、範囲とxrangeは次のように機能します。

range()-メモリ内に新しいリストを作成し、0からNアイテム全体(合計N + 1)を取得して出力します。xrange()-アイテムをスキャンして現在検出されたアイテムのみをメモリに保持するイテレータインスタンスを作成し、常に同じ量のメモリを使用します。

必要な要素がリストの先頭にある場合にのみ、時間とメモリを大幅に節約できます。


1
xrangeイテレータインスタンスを作成しません。これは、xrange反復可能ではあるがイテレータではないオブジェクトを作成します。リストのように、ほとんど(ただし完全ではない)シーケンスです。
abarnert 2015年

1

範囲は、戻りリストをしながらはxrangeを返すはxrangeの範囲を使用する場合には、すべての要素を一度に生成されるのに対し、この場合には、一つだけの要素が生成され、反復ごとに使用可能なように、範囲の大きさにかかわらず、同じメモリを取るオブジェクトおよびメモリで利用可能です。


1

range(..)/ への引数が小さいほど、差は小さくなりますxrange(..)

$ python -m timeit "for i in xrange(10111):" " for k in range(100):" "  pass"
10 loops, best of 3: 59.4 msec per loop

$ python -m timeit "for i in xrange(10111):" " for k in xrange(100):" "  pass"
10 loops, best of 3: 46.9 msec per loop

この場合xrange(100)、効率は約20%だけです。


1

range:-rangeはすべてを一度に入力します。つまり、範囲のすべての数がメモリを占有します。

xrange:-xrangeはジェネレーターのようなものです。数値の範囲が必要な場合に画像に表示されますが、for loop.soでメモリを効率的に使用する場合など、それらを格納したくない場合があります。


1

さらに、do list(xrange(...))は次と同等になりますrange(...)ます。

そう list遅いです。

また xrange、シーケンスを完全に完了していません

それがリストではなくxrangeオブジェクトだからです


1

range() Pythonで 2.x

この関数は、本質的にはrange()Python 2.xで使用可能であった古い関数でありlist、指定された範囲の要素を含むオブジェクトのインスタンスを返します。

ただし、この実装は、ある範囲の数値でリストを初期化する場合、非効率的です。たとえばfor i in range(1000000)、このリストをメモリに格納する必要があるため、メモリと時間の両方の観点から実行するには非常にコストのかかるコマンドになります。


range()Python 3.xおよびxrange()Python2.x

Python 3.xは、の新しい実装を導入しましたrange()(新しい実装は2.xxrange()関数を)。

range()知られている戦略活用遅延評価を。範囲内の要素の膨大なリストを作成する代わりに、新しい実装rangeでは、指定された範囲内の必要な要素を表す軽量なオブジェクトであるclassを導入します。これらは明示的にメモリに格納しません(これはジェネレーターのように聞こえるかもしれませんが、遅延評価の概念は異なる)。


例として、以下を検討してください。

# Python 2.x
>>> a = range(10)
>>> type(a)
<type 'list'>
>>> b = xrange(10)
>>> type(b)
<type 'xrange'>

そして

# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>

-2

この投稿を見るrangeとxrangeの違いを見つけるにを。

引用するには:

range0 xrangeで始まる定義された長さの連続した整数のリストを返します。ただし、「xrangeオブジェクト」を返します。これはイテレータのように機能します


2
これは5歳ですが、その投稿はほとんどすべての点で間違っています。xrangeイテレータではありません。によって返されるrangeリストは反復をサポートします(リストは、ほぼ反復可能な典型的な例です)。の全体的なメリットxrangeは「最小限」ではありません。等々。
abarnert
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.