Quelqu'un peut-il décrire brièvement la différence entre les 2 pour nous les gars non-python? Peut-être que quelque chose comme "xrange () fait tout ce que range () fait, mais prend également en charge X, Y et Z"
Outlaw Programmer
87
range (n) crée une liste contenant tous les entiers 0..n-1. C'est un problème si vous atteignez une plage (1000000), car vous vous retrouverez avec une liste> 4 Mo. xrange gère cela en renvoyant un objet qui prétend être une liste, mais calcule simplement le nombre nécessaire à partir de l'index demandé et le renvoie.
Fondamentalement, alors que range(1000)est un list, xrange(1000)est un objet qui agit comme un generator(bien qu'il n'en soit certainement pas un). Aussi, xrangec'est plus rapide. Vous pouvez import timeit from timeitet ensuite créer une méthode qui a juste for i in xrange: passet une autre pour range, puis faire timeit(method1)et timeit(method2)et, et voilà, xrange est presque deux fois plus rapide parfois (c'est quand vous n'avez pas besoin d'une liste). (Pour moi, pour i in xrange(1000):passvs pour a i in range(1000):passpris 13.316725969314575vs 21.190124988555908secondes respectivement - c'est beaucoup.)
Pour les performances, en particulier lorsque vous itérez sur une large plage, xrange()c'est généralement mieux. Cependant, il existe encore quelques cas pour lesquels vous pourriez préférer range():
En python 3, range()fait ce qui xrange()existait et xrange()n'existe pas. Si vous souhaitez écrire du code qui s'exécutera sur Python 2 et Python 3, vous ne pouvez pas utiliser xrange().
range()peut en fait être plus rapide dans certains cas - par exemple. si itération sur la même séquence plusieurs fois. xrange()doit reconstruire l'objet entier à chaque fois, mais range()aura de vrais objets entiers. (Cependant, il fonctionnera toujours moins bien en termes de mémoire)
xrange()n'est pas utilisable dans tous les cas où une vraie liste est nécessaire. Par exemple, il ne prend pas en charge les tranches ou les méthodes de liste.
[Modifier] Il y a quelques articles mentionnant comment range()sera mis à niveau par l'outil 2to3. Pour mémoire, voici le résultat de l'exécution de l'outil sur certains exemples d'utilisation de range()etxrange()
RefactoringTool:Skipping implicit fixer: buffer
RefactoringTool:Skipping implicit fixer: idioms
RefactoringTool:Skipping implicit fixer: ws_comma
--- range_test.py (original)+++ range_test.py (refactored)@@-1,7+1,7@@for x in range(20):- a=range(20)+ a=list(range(20))
b=list(range(20))
c=[x for x in range(20)]
d=(x for x in range(20))- e=xrange(20)+ e=range(20)
Comme vous pouvez le voir, lorsqu'il est utilisé dans une boucle for ou compréhension, ou lorsqu'il est déjà encapsulé avec list (), la plage reste inchangée.
Que voulez-vous dire par "la gamme deviendra un itérateur"? Cela ne devrait-il pas être "générateur"?
Michael Mior
4
Non. Le générateur fait référence à un type d'itérateur spécifique, et le nouveau rangen'est pas un itérateur de toute façon.
user2357112 prend en charge Monica
Votre deuxième puce n'a pas vraiment de sens. Vous dites que vous ne pouvez pas utiliser un objet plusieurs fois; sûr que vous pouvez! essayez xr = xrange(1,11)alors sur la ligne suivante for i in xr: print " ".join(format(i*j,"3d") for j in xr)et le tour est joué! Vous avez vos horaires jusqu'à dix. Cela fonctionne exactement comme r = range(1,11)et for i in r: print " ".join(format(i*j,"3d") for j in r)... tout est un objet en Python2. Je pense que ce que vous vouliez dire, c'est que vous pouvez faire une compréhension basée sur un index (si cela a du sens) mieux qu'avec rangeplutôt que xrange. La portée est très rare, je pense
dylnmc
(Pas assez de place) Bien, je ne pense que rangepeut être pratique si vous souhaitez utiliser un listdans une boucle, puis modifier certains indices en fonction de certaines conditions ou choses ajouter à cette liste, puis rangeest certainement mieux. Cependant, il xrangeest tout simplement plus rapide et utilise moins de mémoire, donc pour la majorité des applications en boucle, il semble être le meilleur. Il y a des cas - pour en revenir à la question du questionneur - rarement mais existants, où ce rangeserait mieux. Peut-être pas aussi rarement que je le pense, mais j'utilise certainement xrange95% du temps.
dylnmc
129
Non, ils ont tous deux leur utilité:
À utiliser xrange()lors de l'itération, car cela économise de la mémoire. Dire:
for x in xrange(1, one_zillion):
plutôt que:
for x in range(1, one_zillion):
D'un autre côté, utilisez range()si vous voulez réellement une liste de nombres.
multiples_of_seven = range(7,100,7)print"Multiples of seven < 100: ", multiples_of_seven
Vous privilégiez range()plus xrange()que lorsque vous avez besoin d' une liste réelle. Par exemple, lorsque vous souhaitez modifier la liste renvoyée par range(), ou lorsque vous souhaitez la découper. Pour l'itération ou même une indexation normale, xrange()cela fonctionnera bien (et généralement beaucoup plus efficacement). Il y a un point où range()c'est un peu plus rapide que xrange()pour de très petites listes, mais selon votre matériel et divers autres détails, le seuil de rentabilité peut être dû à une longueur de 1 ou 2; pas de quoi s'inquiéter. Je préfère xrange().
Une autre différence est que xrange () ne peut pas prendre en charge des nombres plus grands que les entiers C, donc si vous voulez avoir une plage en utilisant le support de grand nombre intégré à python, vous devez utiliser range ().
Python2.7.3(default,Jul132012,22:29:01)[GCC 4.7.1] on linux2
Type"help","copyright","credits"or"license"for more information.>>> range(123456787676676767676676,123456787676676767676679)[123456787676676767676676L,123456787676676767676677L,123456787676676767676678L]>>> xrange(123456787676676767676676,123456787676676767676679)Traceback(most recent call last):File"<stdin>", line 1,in<module>OverflowError:Python int too large to convert to C long
Python 3 n'a pas ce problème:
Python3.2.3(default,Jul142012,01:01:48)[GCC 4.7.1] on linux2
Type"help","copyright","credits"or"license"for more information.>>> range(123456787676676767676676,123456787676676767676679)
range(123456787676676767676676,123456787676676767676679)
xrange()est plus efficace car au lieu de générer une liste d'objets, il ne génère qu'un objet à la fois. Au lieu de 100 entiers, et de tous leurs frais généraux, et de la liste pour les mettre, vous n'avez qu'un seul entier à la fois. Génération plus rapide, meilleure utilisation de la mémoire, code plus efficace.
À moins d'avoir spécifiquement besoin d'une liste pour quelque chose, je préfère toujours xrange()
range () renvoie une liste, xrange () retourne un objet xrange.
xrange () est un peu plus rapide et un peu plus efficace en mémoire. Mais le gain n'est pas très important.
La mémoire supplémentaire utilisée par une liste n'est bien sûr pas seulement gaspillée, les listes ont plus de fonctionnalités (tranche, répétition, insertion, ...). Les différences exactes peuvent être trouvées dans la documentation . Il n'y a pas de règle stricte, utilisez ce qui est nécessaire.
Python 3.0 est encore en développement, mais la plage IIRC () sera très similaire à xrange () de 2.X et list (range ()) peut être utilisé pour générer des listes.
Je voudrais juste dire qu'il n'est VRAIMENT pas si difficile d'obtenir un objet xrange avec des fonctionnalités de tranche et d'indexation. J'ai écrit du code qui fonctionne assez bien et qui est aussi rapide que xrange quand ça compte (itérations).
from __future__ import division
def read_xrange(xrange_object):# returns the xrange object's start, stop, and step
start = xrange_object[0]if len(xrange_object)>1:
step = xrange_object[1]- xrange_object[0]else:
step =1
stop = xrange_object[-1]+ step
return start, stop, step
classXrange(object):''' creates an xrange-like object that supports slicing and indexing.
ex: a = Xrange(20)
a.index(10)
will work
Also a[:5]
will return another Xrange object with the specified attributes
Also allows for the conversion from an existing xrange object
'''def __init__(self,*inputs):# allow inputs of xrange objectsif len(inputs)==1:
test,= inputs
if type(test)== xrange:
self.xrange = test
self.start, self.stop, self.step = read_xrange(test)return# or create one from start, stop, step
self.start, self.step =0,Noneif len(inputs)==1:
self.stop,= inputs
elif len(inputs)==2:
self.start, self.stop = inputs
elif len(inputs)==3:
self.start, self.stop, self.step = inputs
else:raiseValueError(inputs)
self.xrange = xrange(self.start, self.stop, self.step)def __iter__(self):return iter(self.xrange)def __getitem__(self, item):if type(item)is int:if item <0:
item += len(self)return self.xrange[item]if type(item)is slice:# get the indexes, and then convert to the number
start, stop, step = item.start, item.stop, item.step
start = start if start !=Noneelse0# convert start = None to start = 0if start <0:
start += start
start = self[start]if start <0:raiseIndexError(item)
step =(self.step if self.step !=Noneelse1)*(step if step !=Noneelse1)
stop = stop if stop isnotNoneelse self.xrange[-1]if stop <0:
stop += stop
stop = self[stop]
stop = stop
if stop > self.stop:raiseIndexErrorif start < self.start:raiseIndexErrorreturnXrange(start, stop, step)def index(self, value):
error =ValueError('object.index({0}): {0} not in object'.format(value))
index =(value - self.start)/self.step
if index %1!=0:raise error
index = int(index)try:
self.xrange[index]except(IndexError,TypeError):raise error
return index
def __len__(self):return len(self.xrange)
Honnêtement, je pense que tout le problème est un peu idiot et xrange devrait faire tout cela de toute façon ...
Ouais d'accord; à partir d'une technologie totalement différente, vérifiez le travail sur lodash pour le rendre paresseux: github.com/lodash/lodash/issues/274 . Le tranchage, etc. devrait toujours être aussi paresseux que possible et sinon, réifier ensuite.
Rob Grant
4
Un bon exemple donné dans le livre: Practical Python By Magnus Lie Hetland
Je ne recommanderais pas d'utiliser range au lieu de xrange dans l'exemple précédent - bien que seuls les cinq premiers nombres soient nécessaires, range calcule tous les nombres, ce qui peut prendre beaucoup de temps. Avec xrange, ce n'est pas un problème car il ne calcule que les nombres nécessaires.
Oui, j'ai lu la réponse de @ Brian: En python 3, range () est de toute façon un générateur et xrange () n'existe pas.
Ne fais pas ça. xrange () disparaîtra, mais beaucoup d'autres choses aussi. L'outil que vous utiliserez pour traduire votre code Python 2.x en code Python 3.x traduira automatiquement xrange () en range (), mais range () sera traduit dans la liste moins efficace (range ()).
Thomas Wouters, le
10
Thomas: C'est en fait un peu plus intelligent que ça. Il traduira range () dans les situations où il n'a clairement pas besoin d'une vraie liste (par exemple dans une boucle for, ou de compréhension) en simplement range (). Seuls les cas où il est assigné à une variable ou utilisé directement doivent être encapsulés avec list ()
Brian
2
D'accord, tout le monde ici a une opinion différente sur les compromis et les avantages de xrange par rapport à la plage. Ils sont généralement corrects, xrange est un itérateur, et la plage s'étoffe et crée une liste réelle. Pour la majorité des cas, vous ne remarquerez pas vraiment de différence entre les deux. (Vous pouvez utiliser une carte avec plage mais pas avec xrange, mais elle utilise plus de mémoire.)
Ce que je pense que vous voulez entendre, c'est que le choix préféré est xrange. Étant donné que la plage dans Python 3 est un itérateur, l'outil de conversion de code 2to3 convertira correctement toutes les utilisations de xrange en plage et affichera une erreur ou un avertissement pour les utilisations de la plage. Si vous voulez être sûr de convertir facilement votre code à l'avenir, vous n'utiliserez que xrange et listez (xrange) lorsque vous êtes sûr de vouloir une liste. J'ai appris cela lors du sprint CPython à PyCon cette année (2008) à Chicago.
Ce n'est pas vrai. Le code comme "pour x dans la plage (20)" sera laissé comme plage, et le code comme "x = plage (20)" sera converti en "x = liste (plage (20))" - aucune erreur. De plus, si vous voulez écrire du code qui s'exécutera sous 2.6 et 3.0, range () est votre seule option sans ajouter de fonctions de compatibilité.
Brian
2
range(): range(1, 10)renvoie une liste de 1 à 10 chiffres et conserve toute la liste en mémoire.
xrange(): Comme range(), mais au lieu de renvoyer une liste, renvoie un objet qui génère les nombres dans la plage à la demande. Pour le bouclage, c'est légèrement plus rapide range()et plus efficace en mémoire. xrange()objet comme un itérateur et génère les nombres à la demande (Évaluation paresseuse).
range()fait la même chose que xrange()dans Python 3 et il n’existe pas de terme xrange()dans Python 3.
range()peut en fait être plus rapide dans certains scénarios si vous répétez plusieurs fois la même séquence. xrange()doit reconstruire l'objet entier à chaque fois, mais range()aura de vrais objets entiers.
Bien qu'il xrangesoit plus rapide que rangedans la plupart des cas, la différence de performances est assez minime. Le petit programme ci-dessous compare l'itération sur un rangeet un xrange:
import timeit
# Try various list sizes.for list_len in[1,10,100,1000,10000,100000,1000000]:# Time doing a range and an xrange.
rtime = timeit.timeit('a=0;\nfor n in range(%d): a += n'%list_len, number=1000)
xrtime = timeit.timeit('a=0;\nfor n in xrange(%d): a += n'%list_len, number=1000)# Print the resultprint"Loop list of len %d: range=%.4f, xrange=%.4f"%(list_len, rtime, xrtime)
Les résultats ci-dessous montrent que xrangec'est en effet plus rapide, mais pas suffisant pour transpirer.
Loop list of len 1: range=0.0003, xrange=0.0003Loop list of len 10: range=0.0013, xrange=0.0011Loop list of len 100: range=0.0068, xrange=0.0034Loop list of len 1000: range=0.0609, xrange=0.0438Loop list of len 10000: range=0.5527, xrange=0.5266Loop list of len 100000: range=10.1666, xrange=7.8481Loop list of len 1000000: range=168.3425, xrange=155.8719
Donc, par tous les moyens xrange, mais à moins que vous ne soyez sur un matériel contraint, ne vous en faites pas trop.
range(1000)
est unlist
,xrange(1000)
est un objet qui agit comme ungenerator
(bien qu'il n'en soit certainement pas un). Aussi,xrange
c'est plus rapide. Vous pouvezimport timeit from timeit
et ensuite créer une méthode qui a justefor i in xrange: pass
et une autre pourrange
, puis fairetimeit(method1)
ettimeit(method2)
et, et voilà, xrange est presque deux fois plus rapide parfois (c'est quand vous n'avez pas besoin d'une liste). (Pour moi, pouri in xrange(1000):pass
vs pour ai in range(1000):pass
pris13.316725969314575
vs21.190124988555908
secondes respectivement - c'est beaucoup.)xrange(100)
20% plus rapide querange(100)
.Réponses:
Pour les performances, en particulier lorsque vous itérez sur une large plage,
xrange()
c'est généralement mieux. Cependant, il existe encore quelques cas pour lesquels vous pourriez préférerrange()
:En python 3,
range()
fait ce quixrange()
existait etxrange()
n'existe pas. Si vous souhaitez écrire du code qui s'exécutera sur Python 2 et Python 3, vous ne pouvez pas utiliserxrange()
.range()
peut en fait être plus rapide dans certains cas - par exemple. si itération sur la même séquence plusieurs fois.xrange()
doit reconstruire l'objet entier à chaque fois, maisrange()
aura de vrais objets entiers. (Cependant, il fonctionnera toujours moins bien en termes de mémoire)xrange()
n'est pas utilisable dans tous les cas où une vraie liste est nécessaire. Par exemple, il ne prend pas en charge les tranches ou les méthodes de liste.[Modifier] Il y a quelques articles mentionnant comment
range()
sera mis à niveau par l'outil 2to3. Pour mémoire, voici le résultat de l'exécution de l'outil sur certains exemples d'utilisation derange()
etxrange()
Comme vous pouvez le voir, lorsqu'il est utilisé dans une boucle for ou compréhension, ou lorsqu'il est déjà encapsulé avec list (), la plage reste inchangée.
la source
range
n'est pas un itérateur de toute façon.xr = xrange(1,11)
alors sur la ligne suivantefor i in xr: print " ".join(format(i*j,"3d") for j in xr)
et le tour est joué! Vous avez vos horaires jusqu'à dix. Cela fonctionne exactement commer = range(1,11)
etfor i in r: print " ".join(format(i*j,"3d") for j in r)
... tout est un objet en Python2. Je pense que ce que vous vouliez dire, c'est que vous pouvez faire une compréhension basée sur un index (si cela a du sens) mieux qu'avecrange
plutôt quexrange
. La portée est très rare, je penserange
peut être pratique si vous souhaitez utiliser unlist
dans une boucle, puis modifier certains indices en fonction de certaines conditions ou choses ajouter à cette liste, puisrange
est certainement mieux. Cependant, ilxrange
est tout simplement plus rapide et utilise moins de mémoire, donc pour la majorité des applications en boucle, il semble être le meilleur. Il y a des cas - pour en revenir à la question du questionneur - rarement mais existants, où cerange
serait mieux. Peut-être pas aussi rarement que je le pense, mais j'utilise certainementxrange
95% du temps.Non, ils ont tous deux leur utilité:
À utiliser
xrange()
lors de l'itération, car cela économise de la mémoire. Dire:plutôt que:
D'un autre côté, utilisez
range()
si vous voulez réellement une liste de nombres.la source
Vous privilégiez
range()
plusxrange()
que lorsque vous avez besoin d' une liste réelle. Par exemple, lorsque vous souhaitez modifier la liste renvoyée parrange()
, ou lorsque vous souhaitez la découper. Pour l'itération ou même une indexation normale,xrange()
cela fonctionnera bien (et généralement beaucoup plus efficacement). Il y a un point oùrange()
c'est un peu plus rapide quexrange()
pour de très petites listes, mais selon votre matériel et divers autres détails, le seuil de rentabilité peut être dû à une longueur de 1 ou 2; pas de quoi s'inquiéter. Je préfèrexrange()
.la source
Une autre différence est que xrange () ne peut pas prendre en charge des nombres plus grands que les entiers C, donc si vous voulez avoir une plage en utilisant le support de grand nombre intégré à python, vous devez utiliser range ().
Python 3 n'a pas ce problème:
la source
xrange()
est plus efficace car au lieu de générer une liste d'objets, il ne génère qu'un objet à la fois. Au lieu de 100 entiers, et de tous leurs frais généraux, et de la liste pour les mettre, vous n'avez qu'un seul entier à la fois. Génération plus rapide, meilleure utilisation de la mémoire, code plus efficace.À moins d'avoir spécifiquement besoin d'une liste pour quelque chose, je préfère toujours
xrange()
la source
range () renvoie une liste, xrange () retourne un objet xrange.
xrange () est un peu plus rapide et un peu plus efficace en mémoire. Mais le gain n'est pas très important.
La mémoire supplémentaire utilisée par une liste n'est bien sûr pas seulement gaspillée, les listes ont plus de fonctionnalités (tranche, répétition, insertion, ...). Les différences exactes peuvent être trouvées dans la documentation . Il n'y a pas de règle stricte, utilisez ce qui est nécessaire.
Python 3.0 est encore en développement, mais la plage IIRC () sera très similaire à xrange () de 2.X et list (range ()) peut être utilisé pour générer des listes.
la source
Je voudrais juste dire qu'il n'est VRAIMENT pas si difficile d'obtenir un objet xrange avec des fonctionnalités de tranche et d'indexation. J'ai écrit du code qui fonctionne assez bien et qui est aussi rapide que xrange quand ça compte (itérations).
Honnêtement, je pense que tout le problème est un peu idiot et xrange devrait faire tout cela de toute façon ...
la source
Un bon exemple donné dans le livre: Practical Python By Magnus Lie Hetland
Je ne recommanderais pas d'utiliser range au lieu de xrange dans l'exemple précédent - bien que seuls les cinq premiers nombres soient nécessaires, range calcule tous les nombres, ce qui peut prendre beaucoup de temps. Avec xrange, ce n'est pas un problème car il ne calcule que les nombres nécessaires.
Oui, j'ai lu la réponse de @ Brian: En python 3, range () est de toute façon un générateur et xrange () n'existe pas.
la source
Allez avec gamme pour ces raisons:
1) xrange disparaîtra dans les nouvelles versions de Python. Cela vous donne une compatibilité future facile.
2) la gamme prendra les efficacités associées à xrange.
la source
D'accord, tout le monde ici a une opinion différente sur les compromis et les avantages de xrange par rapport à la plage. Ils sont généralement corrects, xrange est un itérateur, et la plage s'étoffe et crée une liste réelle. Pour la majorité des cas, vous ne remarquerez pas vraiment de différence entre les deux. (Vous pouvez utiliser une carte avec plage mais pas avec xrange, mais elle utilise plus de mémoire.)
Ce que je pense que vous voulez entendre, c'est que le choix préféré est xrange. Étant donné que la plage dans Python 3 est un itérateur, l'outil de conversion de code 2to3 convertira correctement toutes les utilisations de xrange en plage et affichera une erreur ou un avertissement pour les utilisations de la plage. Si vous voulez être sûr de convertir facilement votre code à l'avenir, vous n'utiliserez que xrange et listez (xrange) lorsque vous êtes sûr de vouloir une liste. J'ai appris cela lors du sprint CPython à PyCon cette année (2008) à Chicago.
la source
range()
:range(1, 10)
renvoie une liste de 1 à 10 chiffres et conserve toute la liste en mémoire.xrange()
: Commerange()
, mais au lieu de renvoyer une liste, renvoie un objet qui génère les nombres dans la plage à la demande. Pour le bouclage, c'est légèrement plus rapiderange()
et plus efficace en mémoire.xrange()
objet comme un itérateur et génère les nombres à la demande (Évaluation paresseuse).range()
fait la même chose quexrange()
dans Python 3 et il n’existe pas de termexrange()
dans Python 3.range()
peut en fait être plus rapide dans certains scénarios si vous répétez plusieurs fois la même séquence.xrange()
doit reconstruire l'objet entier à chaque fois, maisrange()
aura de vrais objets entiers.la source
Bien qu'il
xrange
soit plus rapide querange
dans la plupart des cas, la différence de performances est assez minime. Le petit programme ci-dessous compare l'itération sur unrange
et unxrange
:Les résultats ci-dessous montrent que
xrange
c'est en effet plus rapide, mais pas suffisant pour transpirer.Donc, par tous les moyens
xrange
, mais à moins que vous ne soyez sur un matériel contraint, ne vous en faites pas trop.la source
list_len
n'est pas utilisé et vous n'exécutez donc ce code que pour les listes de longueur 100.rtime = timeit.timeit('a=0;\nfor n in range(%d): a += n' % list_len, number=1000)