Apparemment, xrange est plus rapide mais je ne sais pas pourquoi c'est plus rapide (et aucune preuve à part l'anecdotique jusqu'à présent, c'est plus rapide) ou ce qui est différent à propos de
for i in range(0, 20):
for i in xrange(0, 20):
range crée une liste, donc si vous faites range(1, 10000000)
, il crée une liste en mémoire avec des éléments 9999999
.
xrange
est un objet séquence qui évalue paresseusement.
Il faut ajouter à partir de l'allusion de @ Thiago, que dans python3, range correspond à l'équivalent de xrange
range crée une liste, donc si vous faites
range(1, 10000000)
, il crée une liste en mémoire avec des éléments9999999
.
xrange
est un générateur, doncest un objet de séquenceest unqui évalue paresseusement.
Ceci est vrai, mais dans Python 3, .range()
sera implémenté par Python 2 .xrange()
. Si vous devez réellement générer la liste, vous devrez:
list(range(1,100))
N'oubliez pas, utilisez le module timeit
pour tester lequel des petits extraits de code est le plus rapide!
$ 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
Personnellement, j’utilise toujours .range()
, à moins que j’ai affaire à vraiment grandes listes - comme vous pouvez le constater, pour une liste d’un million d’entrées, le temps système supplémentaire n’est que de 0,04 secondes. Et comme le fait remarquer Corey, dans Python 3.0, .xrange()
disparaîtra et .range()
vous donnera de toute façon un comportement de Nice itérateur.
xrange
stocke uniquement les paramètres de plage et génère les nombres à la demande. Cependant, l'implémentation C de Python limite actuellement ses arguments à 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]
Notez que dans Python 3.0, il n'y a que range
et il se comporte comme le 2.x xrange
mais sans les limitations relatives aux points d'extrémité minimum et maximum.
xrange renvoie un itérateur et ne conserve qu'un seul numéro en mémoire à la fois. range conserve la liste complète des nombres en mémoire.
Passez du temps avec le Référence de la bibliothèque . Plus vous maîtriserez le sujet, plus vous pourrez trouver rapidement des réponses à de telles questions. Les premiers chapitres sur les objets et les types intégrés sont particulièrement importants.
L'avantage du type xrange est qu'un objet xrange sera toujours prenez la même quantité de mémoire, quelle que soit la taille de la plage qu’elle représente. Il n'y a aucun avantage de performance cohérent.
Un autre moyen de trouver des informations rapides sur une construction Python est la docstring et la fonction d'aide:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
Je suis choqué que personne ne lise doc :
Cette fonction est très similaire à
range()
, mais renvoie un objetxrange
au lieu d’une liste. Il s'agit d'un type de séquence opaque qui donne les mêmes valeurs que la liste correspondante, sans les stocker toutes en même temps. L’avantage dexrange()
surrange()
est minime (étant donné quexrange()
doit toujours créer les valeurs qui lui sont demandées), sauf si une très grande plage est utilisée sur une machine sans mémoire ou lorsque tous les éléments de la plage ne sont jamais utilisés (par exemple, la boucle est généralement terminée parbreak
).
range crée une liste, donc si vous rangez (1, 10000000), il crée une liste en mémoire avec 10000000 éléments . xrange est un générateur, il évalue donc paresseusement.
Cela vous apporte deux avantages:
MemoryError
.C'est pour des raisons d'optimisation.
range () créera une liste de valeurs du début à la fin (0 .. 20 dans votre exemple). Cela deviendra une opération coûteuse sur de très grandes gammes.
xrange () est en revanche beaucoup plus optimisé. il ne calculera la valeur suivante que si nécessaire (via un objet séquence xrange) et ne crée pas une liste de toutes les valeurs comme le fait range ().
Vous trouverez l'avantage de xrange
sur range
dans cet exemple simple:
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
L'exemple ci-dessus ne reflète rien de bien meilleur en cas de xrange
.
Examinons maintenant le cas suivant où range
est vraiment très lent, comparé à 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
Avec range
, il crée déjà une liste de 0 à 100000000 (fastidieux), mais xrange
est un générateur et génère uniquement des nombres en fonction du besoin, c'est-à-dire si l'itération continue.
En Python-3, l'implémentation de la fonctionnalité range
est identique à celle de xrange
en Python-2, alors qu'ils ont supprimé xrange
en Python-3.
Bonne codage !!
range (): range (1, 10) renvoie une liste de 1 à 10 numéros et conserve la liste entière en mémoire.
xrange (): Comme range (), mais au lieu de renvoyer une liste, retourne un objet qui génère les nombres dans la plage à la demande. Pour le bouclage, ceci est légèrement plus rapide que range () et consomme moins de mémoire . xrange () comme un itérateur et génère les nombres à la demande. (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
range(x,y)
renvoie une liste de chaque nombre compris entre x et y si vous utilisez une boucle for
, alors range
est plus lent. En fait, range
a une plage d'index plus grande. range(x.y)
imprimera une liste de tous les nombres entre x et y
xrange(x,y)
renvoie xrange(x,y)
mais si vous avez utilisé une boucle for
, alors xrange
est plus rapide. xrange
a une plage d'index plus petite. xrange
n’imprimera pas seulement xrange(x,y)
mais conservera tous les nombres qu’il contient.
[In] range(1,10)
[Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
[In] xrange(1,10)
[Out] xrange(1,10)
Si vous utilisez une boucle for
, alors cela fonctionnerait
[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
Il n’ya pas beaucoup de différence lorsqu’on utilise des boucles, bien qu’il y ait une différence lors de l’impression!
En python 2.x
range (x) renvoie une liste créée en mémoire avec x éléments.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange (x) retourne un objet xrange qui est un générateur obj qui génère les nombres à la demande. ils sont calculés pendant la boucle for (Evaluation paresseuse).
Pour le bouclage, cela est légèrement plus rapide que range () et utilise davantage la mémoire.
>>> b = xrange(5)
>>> b
xrange(5)
En testant range contre xrange dans une boucle (je sais que je devrais utiliser timeit , mais cela a été rapidement piraté de mémoire en utilisant un exemple de compréhension de liste simple), j'ai trouvé ce qui suit:
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)
qui donne:
$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?
Ou, en utilisant xrange dans la boucle for:
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
Mon extrait teste-t-il correctement? Des commentaires sur l'instance plus lente de xrange? Ou un meilleur exemple :-)
Certaines des autres réponses mentionnent que Python 3 a supprimé range
de 2.x et renommé xrange
de 2.x en range
. Cependant, à moins que vous n'utilisiez la version 3.0 ou 3.1 (ce que personne ne devrait être), il s'agit en réalité d'un type quelque peu différent.
Comme les documents 3.1 dire:
Les objets Range ont très peu de comportement: ils ne prennent en charge que l'indexation, l'itération et la fonction
len
.
Cependant, dans la version 3.2+, range
est une séquence complète: elle prend en charge les tranches étendues et toutes les méthodes de collections.abc.Sequence
avec la même sémantique que list
.*
Et, au moins dans CPython et PyPy (les deux seules implémentations 3.2+ existantes), il possède également des implémentations à temps constant des méthodes index
et count
et de l'opérateur in
(tant que vous ne lui transmettez que des entiers). Cela signifie que 123456 in r
est raisonnable dans 3.2+, alors que dans 2.7 ou 3.1, ce serait une idée horrible.
* Le fait que issubclass(xrange, collections.Sequence)
renvoie True
dans les versions 2.6-2.7 et 3.0-3.1 est un bogue qui a été corrigé dans la version 3.2 et n'est pas rétroporté.
xrange () et range () en python fonctionnent de la même manière que pour l'utilisateur, mais la différence vient lorsque nous parlons de la façon dont la mémoire est allouée lorsque vous utilisez la fonction.
Lorsque nous utilisons range (), nous allouons de la mémoire pour toutes les variables générées. Il est donc déconseillé de l'utiliser avec un plus grand nombre. des variables à générer.
d'autre part, xrange () ne génère qu'une valeur particulière à la fois et ne peut être utilisé qu'avec la boucle for pour imprimer toutes les valeurs requises.
Lisez le post suivant pour la comparaison entre range et xrange avec une analyse graphique.
range génère la liste complète et la renvoie. xrange ne le fait pas - il génère les nombres de la liste à la demande.
Quoi?range
renvoie une liste statique à l'exécution.xrange
retourne une object
(qui agit comme un générateur, bien que ce n'en soit certainement pas un) à partir de laquelle les valeurs sont générées selon les besoins.
Quand utiliser lequel?
xrange
si vous souhaitez générer une liste pour une étendue gigantesque, disons 1 milliard, en particulier lorsque vous avez un "système sensible à la mémoire" comme un téléphone portable.range
si vous souhaitez parcourir plusieurs fois la liste.PS: fonction range
de Python 3.x == fonction xrange
de Python 2.x.
xrange utilise un itérateur (génère des valeurs à la volée), range renvoie une liste.
La différence diminue pour les arguments plus petits à 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
Dans ce cas, xrange(100)
n’est que d’environ 20% plus efficace.
Si vous souhaitez numériser/imprimer des éléments 0-N, range et xrange fonctionnent comme suit.
range () - crée une nouvelle liste dans la mémoire, prend l'ensemble des éléments 0 à N (totalement N + 1) et les imprime. article rencontré dans la mémoire, utilisant donc la même quantité de mémoire tout le temps.
Si l'élément requis se trouve un peu en tête de la liste, il économisera beaucoup de temps et de mémoire.
Tout le monde l'a beaucoup expliqué. Mais je voulais le voir par moi-même. J'utilise python3. J'ai donc ouvert le moniteur de ressources (sous Windows!) Et d'abord exécuté la commande suivante:
a=0
for i in range(1,100000):
a=a+i
et ensuite vérifié le changement dans la mémoire 'En cours d'utilisation'. C'était insignifiant . Ensuite, j'ai lancé le code suivant:
for i in list(range(1,100000)):
a=a+i
Et il a fallu une grande partie de la mémoire pour l'utiliser, instantanément. Et j’étais convaincu… vous pouvez l’essayer vous-même.
Si vous utilisez Python 2X, remplacez 'range ()' par 'xrange ()' dans le premier code et 'list (range ())' par 'range ()'.
De la documentation d'aide.
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
La différence est apparente. Dans Python 2.x, range
renvoie une liste, xrange
renvoie un objet xrange qui est itérable.
Dans Python 3.x, range
devient xrange
de Python 2.x et xrange
est supprimé.
Range retourne une liste while xrange retourne un xrange objet qui prend la même mémoire quelle que soit la taille de la plage, dans ce cas, un seul élément est généré et disponible par itération alors qu'en cas d'utilisation de range, tous les éléments sont générés à la fois et sont disponibles en mémoire.
range: -range va tout peupler à la fois. Ce qui veut dire que chaque numéro de la plage occupera la mémoire.
xrange: -xrange est quelque chose comme générateur, il entrera en image lorsque vous voulez la plage de nombres mais vous ne voulez pas qu'ils soient stockés, comme lorsque vous voulez utiliser dans pour loop.so mémoire efficace.
De plus, si do list(xrange(...))
sera équivalent à range(...)
.
Donc list
est lent.
De plus, xrange
ne termine vraiment pas complètement la séquence
C'est pourquoi ce n'est pas une liste, c'est un objet xrange