Question

Apparemment, xrange est plus rapide mais je ne sais pas pourquoi c'est plus rapide (et aucune preuve à part l'anecdote jusqu'à présent), ni ce qui est différent à propos de

for i in range(0, 20):
for i in xrange(0, 20):
Était-ce utile?

La solution

range crée une liste. Ainsi, 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 la paresse.

Il convient d'ajouter l'astuce de @ Thiago selon laquelle, dans python3, range correspond à l'équivalent de xrange de python

Autres conseils

  

range crée une liste. Ainsi, 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, il est donc un objet séquence est un qui évalue la paresse.

Cela 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 () , sauf s’il s’agit de vraiment de très grandes listes - comme vous pouvez le voir, en termes de temps, pour une liste de un million d'entrées, la surcharge supplémentaire n'est que de 0,04 seconde. Et comme Corey le fait remarquer, dans Python 3.0, .xrange () disparaîtra et .range () vous donnera quand même un beau comportement d'itérateur.

xrange ne stocke que 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’existe que la plage et se comporte comme le 2.x xrange mais sans les limitations relatives aux extrémités minimales et maximales.

xrange retourne un itérateur et ne garde qu'un seul numéro en mémoire à la fois. gamme conserve la liste complète des numéros en mémoire.

Passez un peu de temps avec la 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’existe aucun avantage en termes de performances.

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)
  

range crée une liste. Ainsi, 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 un MemoryError .
  2. Comme il résout 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.

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 () par rapport à range () est minimal (car xrange () doit encore créer les valeurs qui lui sont demandées) sauf lorsqu'une très grande plage est utilisée sur une machine en manque de mémoire ou lorsque tous les éléments de la plage ne sont jamais utilisés (comme lorsque la boucle se termine généralement par break ).

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 range () le fait.

Vous trouverez l'avantage de xrange sur plage 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ù plage 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 plage , 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, que est, si l'itération continue.

En Python-3, la mise en oeuvre de la fonctionnalité range est identique à celle de xrange en Python-2, alors qu'ils ont supprimé xrange en Python-3

Bon codage !!

plage (): plage (1, 10) renvoie une liste de 1 à 10 chiffres & amp; conservez toute la liste 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, cela est légèrement plus rapide que range () et utilise davantage la 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

plage (x, y) renvoie une liste de chaque nombre compris entre x et y si vous utilisez une boucle pour , puis plage est plus lent. En fait, range a une plage d'index plus grande. range (x.y) affichera une liste de tous les nombres compris entre x et y

xrange (x, y) renvoie xrange (x, y) mais si vous avez utilisé une boucle pour , 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 pour , 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 lorsqu’on l’imprime!

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) renvoie 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 (Évaluation paresseuse).

Pour les boucles, cela est légèrement plus rapide que range () et utilise plus efficacement la mémoire.

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

Lorsque vous testez la portée de xrange dans une boucle (je sais que je devrais utiliser timeit , mais cela a été rapidement piraté de mémoire en utilisant un exemple simple de compréhension de liste) 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 autres réponses mentionnent que Python 3 a supprimé la plage de 2.x et renommé le xrange de la 2.x en plage . Cependant, à moins que vous n'utilisiez la version 3.0 ou 3.1 (ce que personne ne devrait être), il s'agit en fait d'un type quelque peu différent.

En tant que les documents 3.1 sont , par exemple:

  Les objets Range ont très peu de comportement: ils ne supportent que l'indexation, l'itération et la fonction len .

Cependant, dans 3.2+, plage est une séquence complète: il prend en charge les tranches étendues et toutes les méthodes de collections.abc.Sequence avec la même sémantique qu'une liste . *

Et, au moins dans CPython et PyPy (les deux seules implémentations 3.2+ existantes), il dispose également d'implémentations à temps constant des méthodes index et count et l'opérateur dans (tant que vous ne lui transmettez que des entiers). Cela signifie que l'écriture de 123456 dans r est raisonnable dans la version 3.2+, alors que dans la version 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 non 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 pour utiliser 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 no. des variables à générer.

xrange (), d’autre part, 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.

range génère la liste complète et la renvoie. xrange ne le fait pas - il génère les nombres dans la liste à la demande.

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

plage Python par rapport à xrange

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

Quoi?
range renvoie une liste statique à l'exécution.
xrange renvoie un objet (qui agit comme un générateur, même s'il n'en est certainement pas un), à partir duquel les valeurs sont générées à la demande.

Quand utiliser lequel?

  • Utilisez xrange si vous souhaitez générer une liste pour une étendue gigantesque, disons 1 milliard, en particulier lorsque vous disposez d'un "système sensible à la mémoire". comme un téléphone portable.
  • Utilisez plage si vous souhaitez parcourir plusieurs fois la liste.

PS: Fonction de de Python 3.x == Fonction de Python 2.x .

Si vous souhaitez numériser ou imprimer des éléments 0-N, range et xrange fonctionnent comme suit.

range () - crée une nouvelle liste dans la mémoire et prend l’ensemble des éléments 0 à N (totalement N + 1) et les imprime. xrange () - crée une instance d'itérateur qui balaye les éléments et ne garde que l'élément rencontré dans la mémoire, utilisant ainsi la même quantité de mémoire tout le temps.

Si l'élément requis se situe un peu en début de liste, il économisera beaucoup de temps et de mémoire.

La différence diminue pour les arguments plus petits dans la plage (..) / 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.

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 coché la modification dans la mémoire 'En cours d'utilisation'. C'était insignifiant. Ensuite, j'ai exécuté 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 ()".

Range renvoie une liste , tandis que xrange renvoie un objet xrange qui utilise la même mémoire quelle que soit la plage. taille, comme dans ce cas, un seul élément est généré et disponible par itération, tandis qu’en cas d’utilisation de range, tous les éléments sont générés en même temps et sont disponibles dans la mémoire.

range: -range va tout peupler en même temps. Cela signifie que chaque numéro de la plage occupera la mémoire.

xrange: -xrange est quelque chose comme un générateur, il entrera en image quand vous voulez la plage de nombres mais vous ne voulez pas qu'ils soient stockés, comme quand vous voulez utiliser dans pour loop.so une mémoire efficace.

À partir 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, la plage devient xrange de Python 2.x et xrange est supprimé.

De plus, si list (xrange (...)) équivaut à plage (...) .

La liste est donc lente.

De même, xrange ne termine vraiment pas complètement la séquence

C’est pourquoi ce n’est pas une liste, c’est un objet xrange

Consultez cette post pour trouver la différence entre range et xrange. :

Pour citer:

  

plage renvoie exactement ce que vous pensez: une liste de   entiers, d'une longueur définie commençant par 0. xrange , cependant,   retourne un "objet xrange" , qui agit beaucoup comme un itérateur

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top