web-dev-qa-db-fra.com

Quelle est la différence entre les fonctions range et xrange dans Python 2.X?

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):
644
Teifion

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 

735
Charles

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 générateur, donc est un objet de séquence est un qui é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))
215
Corey

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.

103
John Fouhy

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.

64
efotinis

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.

38
Ben Hoffstein

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)
28
Antti Rasinen

Je suis choqué que personne ne lise doc :

Cette fonction est très similaire à range(), mais renvoie un objet xrange 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 de xrange() sur range() est minime (étant donné que xrange() 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 par break).

13
Kishor Pawar

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:

  1. Vous pouvez parcourir des listes plus longues sans obtenir une MemoryError.
  2. En résolvant chaque numéro paresseusement, si vous arrêtez l’itération plus tôt, vous ne perdrez pas de temps à créer la liste complète.
12
Lucas S.

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 ().

10
QAZ

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 !! 

10
User_Targaryen

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
8
Tushar.PUCSD

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!

8
Supercolbat

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)
6
SrmHitter9062

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 :-)

5
Dave Everitt

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é.

5
abarnert

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.

4
Lakshaya Maheshwari

Lisez le post suivant pour la comparaison entre range et xrange avec une analyse graphique.

Gamme Python Vs xrange

3
Harsha Vardhan

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.

3
Eddie Deyo

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? 

  • Utilisez 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.
  • Utilisez range si vous souhaitez parcourir plusieurs fois la liste.

PS: fonction range de Python 3.x == fonction xrange de Python 2.x.

2
kmario23

xrange utilise un itérateur (génère des valeurs à la volée), range renvoie une liste.

2
hacama

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.

1
Evgeni Sergeev

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.

1
SomeDoubts

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 ()'.

1
ANKUR SATYA

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é.

0
Rajendra Uppal

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.

0
user299567

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.

0
tejaswini teju

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

0
U9-Forward