どうやらxrangeは速いのですが、なぜそれが速いのか(そしてこれまでのところ逸話のほかに証明がないのか)、あるいはそれ以外に何が違うのかわかりません。
for i in range(0, 20):
for i in xrange(0, 20):
rangeはリストを作成するので、range(1, 10000000)
を実行すると、メモリ内に9999999
要素を持つリストが作成されます。
xrange
は遅延評価されるシーケンスオブジェクトです。
Python3ではrangeはpythonのxrangeと同等の働きをするという、@ Thiagoのヒントから付け加えるべきです。
rangeはリストを作成するので、
range(1, 10000000)
を実行すると、9999999
要素を使ってメモリ内にリストを作成します。
xrange
ジェネレータなのでシーケンスオブジェクトですそれは怠惰に評価されます。
これは事実ですが、Python 3では.range()
はPython 2 .xrange()
によって実装されます。あなたが実際にリストを生成する必要があるならば、あなたはする必要があるでしょう:
list(range(1,100))
覚えておいて、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()
はイテレータの振る舞いを良くします。
xrange
はrangeパラメータだけを格納し、必要に応じて数値を生成します。しかし、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
のように振る舞いますが、最小と最大のエンドポイントへの制限はありません。
xrangeはイテレータを返し、一度に1つの数だけメモリに保持します。 rangeは数字のリスト全体をメモリに保存します。
Library Reference に時間をかけてください。あなたがそれに慣れているほど、このような質問に対する答えを早く見つけることができます。特に重要なのは、組み込みのオブジェクトと型に関する最初の数章です。
Xrange型の利点は、xrangeオブジェクトが表す範囲のサイズに関係なく、xrangeオブジェクトは常に同じ量のメモリを使用することです。一貫したパフォーマンス上の利点はありません。
Pythonの構成体に関する簡単な情報を見つけるもう一つの方法はdocstringとhelp-functionです:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
私は誰も読んでショックを受けていません doc :
この関数は
range()
に非常に似ていますが、リストの代わりにxrange
オブジェクトを返します。これは不透明なシーケンス型で、対応するリストと同じ値になりますが、実際にはそれらをすべて同時に格納することはしません。メモリ不足のマシンで非常に広い範囲が使用されている場合、または使用されている場合を除き、xrange()
に対するrange()
の利点は最小限です(xrange()
は要求時に値を作成する必要があるため)。範囲のすべての要素が使用されることはありません(通常、ループがbreak
で終了する場合など)。
rangeはリストを作成します。したがって、range(1、10000000)を実行すると、メモリ内に10000000要素のリストが作成されます。 xrangeはジェネレータなので、遅延評価されます。
これには2つの利点があります。
MemoryError
を取得せずに長いリストを繰り返すことができます。最適化のためです。
range()は開始から終了までの値のリストを作成します(あなたの例では0 .. 20)。これは非常に広い範囲では高価な操作になります。
一方、xrange()ははるかに最適化されています。 (xrangeシーケンスオブジェクトを介して)必要なときに次の値を計算するだけで、range()のようにすべての値のリストを作成することはしません。
この簡単な例では、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
機能の実装はPython-2のxrange
の実装と同じですが、Python-3ではxrange
を廃止しました。
ハッピーコーディング!
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
for
ループを使用する場合、range(x,y)
は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
ループを使用しても大きな違いはありませんが、印刷するだけで違いはあります。
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に対してrangeをテストするとき(私は 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の遅いインスタンスについてのコメントはありますか?あるいはもっと良い例:-)
他の回答の中には、Python 3が2.xのrange
を廃止し、2.xのxrange
をrange
に改名したと述べている人もいます。ただし、3.0または3.1を使用しているのでない限り(どちらを使用してもいけない)、実際には多少異なるタイプです。
として3.1ドキュメント 言う:
範囲オブジェクトは、ほとんど動作がありません。それらは、インデックス付け、繰り返し、および
len
関数のみをサポートします。
しかし、3.2以降では、range
は完全なシーケンスです。これは拡張スライス、およびlist
と同じ意味を持つ collections.abc.Sequence
のすべてのメソッドをサポートします。*
そして、少なくともCPythonとPyPy(現在存在する唯一の2つの3.2+実装)では、index
と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で修正されバックポートされませんでした。
pythonのxrange()とrange()はユーザーと同じように動作しますが、違いは両方の関数を使ってメモリがどのように割り当てられるかについて話しているときに生じます。
Range()を使っているときは、それが生成しているすべての変数にメモリを割り当てるので、より大きいnoを付けて使うことはお勧めできません。生成される変数の数。
一方、xrange()は一度に特定の値のみを生成し、forループでのみ使用して必要なすべての値を出力できます。
グラフィカル分析によるrangeとxrangeの比較については、次の記事を読んでください。
rangeはリスト全体を生成してそれを返します。 xrangeはしません - 要求に応じてリストに数字を生成します。
何?range
は実行時に静的リストを返します。xrange
は、必要に応じて必要に応じて値が生成されるobject
(これは確かに1つではありませんが、ジェネレータのように機能します)を返します。
いつ使うの?
xrange
を使用してください。range
を使用してください。シモンズ:Python 3.xのrange
関数== Python 2.xのxrange
関数。
xrangeはイテレータを使用し(その場で値を生成します)、rangeはリストを返します。
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%です。
0〜N項目のスキャン/印刷の要件では、rangeとxrangeは次のように機能します。
range() - メモリに新しいリストを作成し、0からNまでの項目全体(合計N + 1)を取り出してそれらを印刷します。 xrange() - アイテムをスキャンして現在遭遇しているアイテムだけをメモリに保存するイテレータインスタンスを作成します。したがって、常に同じ量のメモリを使用します。
必要な要素がリストの先頭にある場合は、かなりの時間とメモリを節約できます。
誰もがそれを大いに説明しました。しかし、私は自分自身でそれを見ることを望みました。私は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()'にそれぞれ置き換えてください。
ヘルプドキュメントから。
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
はPython 2.xのxrange
になり、xrange
は削除されました。
Range は list を返します/ while xrange は範囲サイズに関係なく同じメモリを使用する xrange オブジェクトを返します。一方、rangeを使用する場合は、すべての要素が一度に生成され、メモリ内で利用可能になります。
range:-rangeは、一度にすべてを設定します。つまり、範囲内のすべての番号がメモリを占有します。
xrange:-xrangeはgeneratorのようなものです。数値の範囲が欲しいときには思い浮かぶでしょうが、for loop.soでメモリ効率を上げたいときのように、それらを格納したくないのです。
さらに、do list(xrange(...))
がrange(...)
と同等になります。
だからlist
は遅いです。
またxrange
は実際には完全にシーケンスを終了しません
だから、リストではなく、xrange
オブジェクトなのです。