Algunas medidas de rendimiento, utilizando en timeitlugar de intentar hacerlo manualmente time.
Primero, Apple 2.7.2 de 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
Ahora, python.org 3.3.0 de 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
Al parecer, 3.x rangerealidad es un poco más lento que 2.x xrange. Y la xrangefunción del OP no tiene nada que ver con eso. (No es sorprendente, ya que __iter__no es probable que una llamada única a la ranura sea visible entre 10000000 llamadas a lo que ocurra en el bucle, pero alguien lo mencionó como una posibilidad).
Pero es solo un 30% más lento. ¿Cómo llegó el OP 2 veces más lento? Bueno, si repito las mismas pruebas con Python de 32 bits, obtengo 1.58 vs. 3.12. Entonces, supongo que este es otro de esos casos en los que 3.x ha sido optimizado para un rendimiento de 64 bits en formas que perjudican a 32 bits.
pero, realmente importa? Mira esto, con 3.3.0 64 bits nuevamente:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Por lo tanto, construir el listtoma más del doble de tiempo que la iteración completa.
Y en cuanto a "consume muchos más recursos que Python 2.6+", según mis pruebas, parece que un 3.x rangetiene exactamente el mismo tamaño que un 2.x xrange, e, incluso si fuera 10 veces más grande, construir la lista innecesaria sigue siendo aproximadamente 10000000x un problema mayor que cualquier cosa que la iteración de rango pueda hacer.
¿Y qué hay de un forbucle explícito en lugar del bucle C dentro 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
Entonces, casi tanto tiempo perdido en la fordeclaración como en el trabajo real de iterar el range.
Si le preocupa optimizar la iteración de un objeto de rango, probablemente esté buscando en el lugar equivocado.
Mientras tanto, sigues preguntando por qué xrange se eliminó, no importa cuántas veces la gente le diga lo mismo, pero lo repetiré nuevamente: no se eliminó: se cambió el nombre a range, y el 2.x rangees lo que se eliminó.
Aquí hay alguna prueba de que el rangeobjeto 3.3 es un descendiente directo del xrangeobjeto 2.x (y no de la rangefunción 2.x ): la fuente de 3.3range y 2.7xrange . Incluso puede ver el historial de cambios (vinculado, creo, al cambio que reemplazó la última instancia de la cadena "xrange" en cualquier parte del archivo).
Entonces, ¿por qué es más lento?
Bueno, por un lado, han agregado muchas características nuevas. Por otro lado, han realizado todo tipo de cambios en todo el lugar (especialmente dentro de la iteración) que tienen efectos secundarios menores. Y ha habido mucho trabajo para optimizar dramáticamente varios casos importantes, incluso si a veces pesimiza ligeramente los casos menos importantes. Agregue todo esto, y no me sorprende que iterar lo rangemás rápido posible ahora sea un poco más lento. Es uno de esos casos menos importantes en los que nadie se preocuparía lo suficiente. Es probable que nadie tenga un caso de uso real en el que esta diferencia de rendimiento sea el punto clave en su código.
rangeen Python 3.x esxrangede Python 2.x. De hecho, Python 2.x'srangefue eliminado.