Récemment, j'ai commencé à utiliser Python3 et son manque de xrange fait mal.
Exemple simple:
1) Python2:
from time import time as t
def count():
st = t()
[x for x in xrange(10000000) if x%4 == 0]
et = t()
print et-st
count()
2) Python3:
from time import time as t
def xrange(x):
return iter(range(x))
def count():
st = t()
[x for x in xrange(10000000) if x%4 == 0]
et = t()
print (et-st)
count()
Les résultats sont respectivement:
1) 1,53888392448 2) 3,215819835662842
Pourquoi donc? Je veux dire, pourquoi xrange a été supprimé? C'est un excellent outil pour apprendre. Pour les débutants, tout comme moi, comme nous l'étions tous à un moment donné. Pourquoi l'enlever? Quelqu'un peut-il m'indiquer le PEP approprié, je ne le trouve pas.
À votre santé.
python
python-3.x
pep
xrange
catalesia
la source
la source
range
en Python 3.x estxrange
de Python 2.x. Ce sont en fait les Python 2.xrange
qui ont été supprimés.time
. En plus d'être plus facile à utiliser et plus difficile de se tromper, et de répéter les tests pour vous,timeit
prend soin de toutes sortes de choses dont vous ne vous souviendrez pas, ou même ne savez pas comment vous en occuper (comme désactiver le GC), et pouvez utiliser un horloge avec des milliers de fois une meilleure résolution.range
surx%4 == 0
? Pourquoi ne pas simplement testerlist(xrange())
vslist(range())
, donc il y a aussi peu de travail étranger que possible? (Par exemple, comment savez-vous que 3.x ne fonctionne pasx%4
plus lentement?) D'ailleurs, pourquoi construisez-vous un énormelist
, ce qui implique beaucoup d'allocation de mémoire (qui, en plus d'être lent, est également incroyablement variable) ?iter(range)
est redondant.list(range(..))
. Cela équivaut à la plage de python 2. Ou pour le dire d'une autre manière: xrange a été renommé plage, car c'est la meilleure valeur par défaut; il n'était pas nécessaire d'avoir les deux,list(range)
si vous avez vraiment besoin d'une liste. .Réponses:
Certaines mesures de performances, en utilisant
timeit
au lieu d'essayer de le faire manuellement avectime
.Tout d'abord, Apple 2.7.2 64 bits:
Maintenant, python.org 3.3.0 64 bits:
Apparemment, 3.x
range
est vraiment un peu plus lent que 2.xxrange
. Et laxrange
fonction de l'OP n'a rien à voir avec cela. (Pas étonnant, car un appel unique à l'__iter__
emplacement n'est probablement pas visible parmi 10000000 appels à tout ce qui se passe dans la boucle, mais quelqu'un l'a évoqué comme une possibilité.)Mais c'est seulement 30% plus lent. Comment l'OP est-il devenu 2x plus lent? Eh bien, si je répète les mêmes tests avec Python 32 bits, j'obtiens 1,58 contre 3,12. Donc, je suppose que c'est encore un autre de ces cas où 3.x a été optimisé pour des performances 64 bits d'une manière qui nuit à 32 bits.
Mais est-ce que c'est vraiment important? Vérifiez cela, avec 3.3.0 64 bits à nouveau:
Ainsi, la construction de
list
prend plus de deux fois plus de temps que l'itération entière.Et quant à «consomme beaucoup plus de ressources que Python 2.6+», d'après mes tests, il semble qu'un 3.x
range
soit exactement de la même taille qu'un 2.xxrange
- et, même s'il était 10 fois plus grand, la construction de la liste inutile est toujours environ 10000000x plus un problème que tout ce que l'itération de plage pourrait faire.Et qu'en est-il d'une
for
boucle explicite au lieu de la boucle C à l'intérieurdeque
?Donc, presque autant de temps perdu dans la
for
déclaration que dans le travail réel d'itération de larange
.Si vous craignez d'optimiser l'itération d'un objet de plage, vous cherchez probablement au mauvais endroit.
Pendant ce temps, vous continuez à demander pourquoi a
xrange
été supprimé, peu importe le nombre de fois que les gens vous disent la même chose, mais je vais le répéter: il n'a pas été supprimé: il a été renommérange
et le 2.xrange
est ce qui a été supprimé.Voici une preuve que l'
range
objet 3.3 est un descendant direct de l'xrange
objet 2.x (et non de larange
fonction 2.x ): la source de 3.3range
et 2.7xrange
. Vous pouvez même voir l' historique des modifications (lié, je crois, à la modification qui a remplacé la dernière instance de la chaîne "xrange" n'importe où dans le fichier).Alors, pourquoi est-ce plus lent?
Eh bien, pour commencer, ils ont ajouté beaucoup de nouvelles fonctionnalités. D'autre part, ils ont fait toutes sortes de changements partout (en particulier à l'intérieur de l'itération) qui ont des effets secondaires mineurs. Et il y avait eu beaucoup de travail pour optimiser considérablement divers cas importants, même si cela pessimise parfois légèrement les cas moins importants. Ajoutez tout cela, et je ne suis pas surpris que l'itération
range
aussi rapide que possible soit maintenant un peu plus lente. C'est l'un de ces cas moins importants sur lesquels personne ne se soucierait jamais suffisamment de se concentrer. Personne n'est susceptible d'avoir un cas d'utilisation réel où cette différence de performances est le point chaud dans leur code.la source
range
. L'range
objet en 3.3 est un descendant direct de l'xrange
objet en 2.7, pas de larange
fonction en 2.7. C'est comme demander alors que aitertools.imap
été supprimé en faveur demap
. Il n'y a pas de réponse, car rien de tel ne s'est produit.range
certain temps sans rien faire d'autre.La gamme de python3 est le xrange de python2. Il n'est pas nécessaire d'envelopper un iter autour de lui. Pour obtenir une liste réelle en Python3, vous devez utiliser
list(range(...))
Si vous voulez quelque chose qui fonctionne avec Python2 et Python3, essayez ceci
la source
range
etxrange
se comportera différemment. Il ne suffit pas de le faire, il faudrait également s'assurer de ne jamais supposer que celarange
renvoie une liste (comme ce serait le cas en python 2).futurize
outil pour convertir automatiquement votre code source: python-future.org/…Le
range
type de Python 3 fonctionne exactement comme Python 2xrange
. Je ne sais pas pourquoi vous voyez un ralentissement, car l'itérateur renvoyé par votrexrange
fonction est exactement ce que vous obtiendriez si vous répétiezrange
directement.Je ne parviens pas à reproduire le ralentissement sur mon système. Voici comment j'ai testé:
Python 2, avec
xrange
:Python 3, avec
range
est un tout petit peu plus rapide:J'ai récemment appris que le
range
type de Python 3 possède d'autres fonctionnalités intéressantes, telles que la prise en charge du découpage:range(10,100,2)[5:25:5]
c'estrange(20, 60, 10)
!la source
xrange
fois tant de fois, ou est-ce fait qu'une seule fois?xrange
n'a pas été supprimé, juste renommé .range
moi, la plus grosse victoire en 3.x est le temps constant__contains__
. Les débutants écrivaient300000 in xrange(1000000)
et cela faisait itérer l'ensemblexrange
(ou au moins les 30 premiers%), nous avons donc dû expliquer pourquoi c'était une mauvaise idée, même si cela avait l'air si pythonique. Maintenant, il est pythonique.Une façon de corriger votre code python2 est:
la source
range = xrange
qui est en commentaire par @John La Royxrange = range
... j'ai changé de relevéxrange de Python 2 est un générateur et implémente un itérateur tandis que la plage n'est qu'une fonction. En Python3, je ne sais pas pourquoi a été abandonné le xrange.
la source
range()
est l'équivalent de PY2xrange()
. Et donc dans PY3xrange()
est redondant.comp: ~ $ python Python 2.7.6 (par défaut, 22 juin 2015, 17:58:13) [GCC 4.8.2] sur linux2
5.656799077987671
5.579368829727173
21.54827117919922
22.014557123184204
Avec timeit number = 1 param:
0,2245171070098877
0,10750913619995117
comp: ~ $ python3 Python 3.4.3 (par défaut, 14 octobre 2015, 20:28:29) [GCC 4.8.4] sous linux
9.113872020003328
9.07014398300089
Avec timeit number = 1,2,3,4 param fonctionne rapidement et de manière linéaire:
0,09329321900440846
0,18501482300052885
0,2703447980020428
0,36209142999723554
Il semble donc que si nous mesurons 1 cycle de boucle en cours comme timeit.timeit ("[x pour x dans la plage (1000000) si x% 4]", nombre = 1) (comme nous l'utilisons réellement dans le code réel) python3 fonctionne assez rapidement, mais dans les boucles répétées, python 2 xrange () gagne en vitesse contre range () de python 3.
la source