Antworten:
In Python 2.x:
range
Erstellt eine Liste. Wenn Sie dies tun range(1, 10000000)
, wird eine Liste mit 9999999
Elementen im Speicher erstellt .
xrange
ist ein Sequenzobjekt, das träge ausgewertet wird.
In Python 3 range
entspricht dies Python xrange
, und um die Liste zu erhalten, müssen Sie verwenden list(range(...))
.
xrange(x).__iter__()
ist ein Generator.
i
bei Bedarf und nicht bei der Initialisierung ausgewertet wird.
range erstellt eine Liste. Wenn Sie dies tun
range(1, 10000000)
, wird eine Liste mit9999999
Elementen im Speicher erstellt .
xrange
ein Generator ist, so dass eseine Sequenz Objekta ist, dass auswertet lazily.
Dies ist wahr, wird aber in Python 3 .range()
von Python 2 implementiert .xrange()
. Wenn Sie die Liste tatsächlich generieren müssen, müssen Sie Folgendes tun:
list(range(1,100))
xrange
einen Generator anzurufen? Es ist eine Funktion, die eine yield
Anweisung enthält, und laut Glossar werden solche Funktionen Generatoren genannt.
Denken Sie daran, timeit
testen Sie mit dem Modul, welcher der kleinen Codeausschnitte schneller ist!
$ 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
Persönlich verwende ich immer .range()
, es sei denn, ich habe es mit wirklich großen Listen zu tun - wie Sie zeitlich sehen können, beträgt der zusätzliche Aufwand für eine Liste mit einer Million Einträgen nur 0,04 Sekunden. Und wie Corey betont, wird Python 3.0 .xrange()
verschwinden und .range()
Ihnen trotzdem ein gutes Iteratorverhalten geben.
python -m timeit "for i in xrange(1000000):" " pass"
the extra overhead is only 0.04 seconds
Ist nicht die richtige Sichtweise, (90.5-51.1)/51.1 = 1.771 times slower
ist richtig, weil sie vermittelt, dass dies möglicherweise ein Engpass sein kann, wenn dies die Kernschleife Ihres Programms ist. Wenn dies jedoch ein kleiner Teil ist, ist 1,77x nicht viel.
xrange
speichert nur die Bereichsparameter und generiert die Nummern bei Bedarf. Die C-Implementierung von Python beschränkt ihre Argumente derzeit jedoch auf C-Longs:
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]
Beachten Sie, dass es in Python 3.0 nur gibt range
und es sich wie 2.x verhält, xrange
jedoch ohne die Einschränkungen für minimale und maximale Endpunkte.
xrange gibt einen Iterator zurück und speichert jeweils nur eine Zahl. Der Bereich speichert die gesamte Liste der Zahlen.
xrange
gibt keinen Iterator zurück.
and only keeps one number in memory at a time
und wo der Rest platziert ist,
Verbringen Sie einige Zeit mit der Bibliotheksreferenz . Je vertrauter Sie damit sind, desto schneller finden Sie Antworten auf solche Fragen. Besonders wichtig sind die ersten Kapitel über eingebaute Objekte und Typen.
Der Vorteil des xrange-Typs besteht darin, dass ein xrange-Objekt unabhängig von der Größe des Bereichs, den es darstellt, immer dieselbe Speichermenge benötigt. Es gibt keine konsistenten Leistungsvorteile.
Eine andere Möglichkeit, schnelle Informationen zu einem Python-Konstrukt zu finden, ist die Dokumentzeichenfolge und die Hilfefunktion:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
Ich bin schockiert, dass niemand doc gelesen hat :
Diese Funktion ist sehr ähnlich,
range()
gibt jedoch einxrange
Objekt anstelle einer Liste zurück. Dies ist ein undurchsichtiger Sequenztyp, der dieselben Werte wie die entsprechende Liste liefert, ohne sie alle gleichzeitig zu speichern. Der Vorteil vonxrange()
overrange()
ist minimal (daxrange()
die Werte immer noch erstellt werden müssen, wenn Sie danach gefragt werden), außer wenn ein sehr großer Bereich auf einer Maschine mit Speichermangel verwendet wird oder wenn alle Elemente des Bereichs niemals verwendet werden (z. B. wenn die Schleife verwendet wird) normalerweise beendet mitbreak
).
range erstellt eine Liste. Wenn Sie also range (1, 10000000) ausführen, wird eine Liste mit 10000000 Elementen im Speicher erstellt. xrange ist ein Generator und wird daher träge ausgewertet.
Dies bringt Ihnen zwei Vorteile:
MemoryError
.In diesem einfachen Beispiel finden Sie den Vorteil von xrange
over 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
Das obige Beispiel spiegelt im Fall von nichts wesentlich Besseres wider xrange
.
Schauen Sie sich nun den folgenden Fall an range
, in dem es im Vergleich zu wirklich sehr, sehr langsam ist 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
Mit erstellt range
es bereits eine Liste von 0 bis 100000000 (zeitaufwändig), xrange
ist jedoch ein Generator und generiert nur Zahlen basierend auf dem Bedarf, dh wenn die Iteration fortgesetzt wird.
In Python-3 ist die Implementierung der range
Funktionalität dieselbe wie xrange
in Python-2, während sie xrange
in Python-3 abgeschafft wurde
Viel Spaß beim Codieren !!
Es ist aus Optimierungsgründen.
range () erstellt eine Liste von Werten von Anfang bis Ende (0 .. 20 in Ihrem Beispiel). Dies wird in sehr großen Bereichen zu einer teuren Operation.
xrange () ist dagegen viel optimierter. Der nächste Wert wird nur bei Bedarf berechnet (über ein xrange-Sequenzobjekt) und es wird keine Liste aller Werte erstellt, wie dies bei range () der Fall ist.
range(x,y)
Gibt eine Liste jeder Zahl zwischen x und y zurück, wenn Sie eine for
Schleife verwenden, und range
ist dann langsamer. In der Tat range
hat einen größeren Indexbereich. range(x.y)
druckt eine Liste aller Zahlen zwischen x und y aus
xrange(x,y)
Gibt zurück, xrange(x,y)
aber wenn Sie eine for
Schleife verwendet haben, xrange
ist dies schneller. xrange
hat einen kleineren Indexbereich. xrange
druckt nicht nur aus, xrange(x,y)
sondern behält auch alle darin enthaltenen Nummern bei.
[In] range(1,10)
[Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
[In] xrange(1,10)
[Out] xrange(1,10)
Wenn Sie eine for
Schleife verwenden, würde es funktionieren
[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
Es gibt keinen großen Unterschied bei der Verwendung von Loops, obwohl es einen Unterschied beim Drucken gibt!
range (): range (1, 10) gibt eine Liste mit 1 bis 10 Zahlen zurück und speichert die gesamte Liste.
xrange (): Wie range (), aber anstatt eine Liste zurückzugeben, wird bei Bedarf ein Objekt zurückgegeben, das die Zahlen im Bereich generiert. Für Schleifen ist dies etwas schneller als range () und speichereffizienter. xrange () Objekt wie ein Iterator und generiert die Zahlen bei Bedarf. (Lazy Evaluation)
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
Einige der anderen Antworten erwähnt , dass Python 3 2.x ist eliminiert range
und umbenannt 2.x ist xrange
zu range
. Wenn Sie jedoch nicht 3.0 oder 3.1 verwenden (was niemand sein sollte), handelt es sich tatsächlich um einen etwas anderen Typ.
Wie die 3.1-Dokumente sagen:
Bereichsobjekte haben nur ein sehr geringes Verhalten: Sie unterstützen nur die Indizierung, Iteration und die
len
Funktion.
In Version 3.2+ range
handelt es sich jedoch um eine vollständige Sequenz - sie unterstützt erweiterte Slices und alle Methoden collections.abc.Sequence
mit derselben Semantik wie a list
. * *
Und zumindest in CPython und PyPy (die einzigen zwei 3.2+ Implementierungen , die derzeit vorhanden ist ), hat es auch konstante Zeit Implementierungen der index
und count
Methoden und die in
Betreiber (solange man es nur ganze Zahlen passieren). Dies bedeutet, dass das Schreiben 123456 in r
in 3.2+ vernünftig ist, während es in 2.7 oder 3.1 eine schreckliche Idee wäre.
* Die Tatsache , dass issubclass(xrange, collections.Sequence)
Erträge True
in 2,6-2,7 und 3,0-3,1 ist ein Fehler , der in 3.2 und nicht zurückportiert wurde behoben.
In Python 2.x.
range (x) gibt eine Liste zurück, die mit x Elementen im Speicher erstellt wird.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange (x) gibt ein xrange-Objekt zurück, das ein Generatorobjekt ist, das die Zahlen bei Bedarf generiert. Sie werden während der for-Schleife (Lazy Evaluation) berechnet.
Für Schleifen ist dies etwas schneller als range () und speichereffizienter.
>>> b = xrange(5)
>>> b
xrange(5)
xrange()
ist kein Generator. xrange(n)
.__ iter __ () `ist.
Beim Testen des Bereichs gegen xrange in einer Schleife (ich weiß, ich sollte timeit verwenden , aber dies wurde mithilfe eines einfachen Beispiels zum Listenverständnis schnell aus dem Speicher gehackt) fand ich Folgendes:
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)
was gibt:
$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?
Oder verwenden Sie xrange in der for-Schleife:
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
Wird mein Snippet richtig getestet? Irgendwelche Kommentare zur langsameren Instanz von xrange? Oder ein besseres Beispiel :-)
xrange
schien etwas schneller zu sein, obwohl der Vergleich mit Python 3 jetzt überflüssig ist.
timeit
. Es kümmert sich darum, viele Male zu laufen, GC zu deaktivieren, die beste Uhr anstelle von time
usw. zu verwenden
xrange () und range () in Python funktionieren ähnlich wie für den Benutzer, aber der Unterschied ergibt sich, wenn wir darüber sprechen, wie der Speicher bei Verwendung beider Funktionen zugewiesen wird.
Wenn wir range () verwenden, weisen wir allen von ihm generierten Variablen Speicher zu. Daher wird die Verwendung mit der größeren Zahl nicht empfohlen. von zu generierenden Variablen.
xrange () hingegen generiert jeweils nur einen bestimmten Wert und kann nur mit der for-Schleife verwendet werden, um alle erforderlichen Werte zu drucken.
range generiert die gesamte Liste und gibt sie zurück. xrange nicht - es generiert bei Bedarf die Nummern in der Liste.
Was?
range
Gibt zur Laufzeit eine statische Liste zurück.
xrange
Gibt ein object
(das sich wie ein Generator verhält, obwohl es sicherlich keines ist) zurück, aus dem bei Bedarf Werte generiert werden.
Wann welche verwenden?
xrange
Sie diese Option, wenn Sie eine Liste für einen gigantischen Bereich erstellen möchten, z. B. 1 Milliarde, insbesondere wenn Sie ein "speicherempfindliches System" wie ein Mobiltelefon haben.range
Sie diese Option, wenn Sie die Liste mehrmals durchlaufen möchten.PS: Python 3.x die range
Funktion == Python 2.x - xrange
Funktion.
xrange
gibt kein Generatorobjekt zurück.
Jeder hat es sehr erklärt. Aber ich wollte, dass es es selbst sieht. Ich benutze Python3. Also öffnete ich den Ressourcenmonitor (unter Windows!) Und führte zuerst den folgenden Befehl aus:
a=0
for i in range(1,100000):
a=a+i
und überprüfte dann die Änderung im 'In Use'-Speicher. Es war unbedeutend. Dann habe ich den folgenden Code ausgeführt:
for i in list(range(1,100000)):
a=a+i
Und es brauchte sofort einen großen Teil des Speichers, um verwendet zu werden. Und ich war überzeugt. Sie können es selbst versuchen.
Wenn Sie Python 2X verwenden, ersetzen Sie 'range ()' im ersten Code durch 'xrange ()' und 'list (range ())' durch 'range ()'.
Aus den Hilfedokumenten.
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
Der Unterschied ist offensichtlich. Gibt in Python 2.x range
eine Liste und xrange
ein iterierbares xrange-Objekt zurück.
Wird in Python 3.x range
zu xrange
Python 2.x und xrange
wird entfernt.
Bei einer Anforderung zum Scannen / Drucken von 0-N-Elementen funktionieren Bereich und x-Bereich wie folgt.
range () - Erstellt eine neue Liste im Speicher und nimmt die gesamten 0 bis N Elemente (insgesamt N + 1) und druckt sie aus. xrange () - Erstellt eine Iteratorinstanz, die die Elemente durchsucht und nur das aktuell angetroffene Element im Speicher behält, wodurch immer die gleiche Speichermenge verwendet wird.
Wenn sich das erforderliche Element nur etwas am Anfang der Liste befindet, spart dies viel Zeit und Speicher.
xrange
erstellt keine Iteratorinstanz. Es wird ein xrange
Objekt erstellt, das iterierbar ist, aber kein Iterator - fast (aber nicht ganz) eine Sequenz wie eine Liste.
Range gibt eine Liste zurück, während xrange ein xrange- Objekt zurückgibt , das unabhängig von der Bereichsgröße denselben Speicher belegt. In diesem Fall wird nur ein Element pro Iteration generiert und ist verfügbar, während bei Verwendung von range alle Elemente gleichzeitig und generiert werden sind im Speicher verfügbar.
Der Unterschied verringert sich für kleinere Argumente zu 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
In diesem Fall xrange(100)
ist nur etwa 20% effizienter.
range: -range füllt alles auf einmal. Dies bedeutet, dass jede Nummer des Bereichs den Speicher belegt.
xrange: -xrange ist so etwas wie ein Generator. Es wird angezeigt, wenn Sie den Zahlenbereich möchten, aber nicht möchten, dass sie gespeichert werden, wie wenn Sie in for loop.so speichereffizient verwenden möchten.
Darüber hinaus ist if do list(xrange(...))
gleichbedeutend mit range(...)
.
Ist list
also langsam.
xrange
Beendet die Sequenz auch wirklich nicht vollständig
Deshalb ist es keine Liste, sondern ein xrange
Objekt
range()
in Python 2.x
Diese Funktion ist im Wesentlichen die alte range()
Funktion, die in Python verfügbar war, 2.x
und gibt eine Instanz eines list
Objekts zurück, das die Elemente im angegebenen Bereich enthält.
Diese Implementierung ist jedoch zu ineffizient, wenn eine Liste mit einem Zahlenbereich initialisiert werden soll. Zum Beispiel for i in range(1000000)
wäre die Ausführung eines Befehls sehr teuer, sowohl in Bezug auf den Speicher als auch in Bezug auf die Zeitnutzung, da die Speicherung dieser Liste im Speicher erforderlich ist.
range()
in Python 3.x
und xrange()
in Python2.x
Python 3.x
führte eine neuere Implementierung von ein range()
(während die neuere Implementierung bereits in Python 2.x
über die xrange()
Funktion verfügbar war ).
Das range()
nutzt eine Strategie, die als Lazy Evaluation bekannt ist. Anstatt eine große Liste von Elementen im Bereich zu erstellen, führt die neuere Implementierung die Klasse ein range
, ein leichtes Objekt, das die erforderlichen Elemente im angegebenen Bereich darstellt, ohne sie explizit im Speicher zu speichern (dies mag nach Generatoren klingen, aber das Konzept der verzögerten Auswertung ist es anders).
Betrachten Sie als Beispiel Folgendes:
# Python 2.x
>>> a = range(10)
>>> type(a)
<type 'list'>
>>> b = xrange(10)
>>> type(b)
<type 'xrange'>
und
# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>
In diesem Beitrag finden Sie den Unterschied zwischen Bereich und Bereich:
Zitieren:
range
Gibt genau das zurück, was Sie denken: Eine Liste aufeinanderfolgender Ganzzahlen mit einer definierten Länge, die mit 0 beginntxrange
, gibt jedoch ein "xrange-Objekt" zurück , das sich stark wie ein Iterator verhält
xrange
ist kein Iterator. Die von zurückgegebene Liste range
unterstützt die Iteration (eine Liste ist so ziemlich das prototypische Beispiel einer iterierbaren Liste). Der Gesamtnutzen von xrange
ist nicht "minimal". Und so weiter.