Certaines mesures de performances, en utilisant timeitau lieu d'essayer de le faire manuellement avec time.
Tout d'abord, Apple 2.7.2 64 bits:
In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.05 s per loop
Maintenant, python.org 3.3.0 64 bits:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.32 s per loop
In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.31 s per loop
In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.33 s per loop
Apparemment, 3.x rangeest vraiment un peu plus lent que 2.x xrange. Et la xrangefonction 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:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Ainsi, la construction de listprend 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 rangesoit exactement de la même taille qu'un 2.x xrange- 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 forboucle explicite au lieu de la boucle C à l'intérieur deque?
In [87]: def consume(x):
....: for i in x:
....: pass
In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0)
1 loops, best of 3: 1.85 s per loop
Donc, presque autant de temps perdu dans la fordéclaration que dans le travail réel d'itération de la range.
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é rangeet le 2.x rangeest ce qui a été supprimé.
Voici une preuve que l' rangeobjet 3.3 est un descendant direct de l' xrangeobjet 2.x (et non de la rangefonction 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 rangeaussi 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.
rangeen Python 3.x estxrangede Python 2.x. Ce sont en fait les Python 2.xrangequi ont été supprimés.