Recientemente comencé a usar Python3 y me duele la falta de xrange.
Ejemplo 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()
Los resultados son, respectivamente:
1) 1.53888392448 2) 3.215819835662842
¿Porqué es eso? Quiero decir, ¿por qué se ha eliminado xrange? Es una gran herramienta para aprender. Para los principiantes, como yo, como todos estábamos en algún momento. ¿Por qué eliminarlo? ¿Alguien puede señalarme la PEP adecuada? No puedo encontrarla.
Salud.
python
python-3.x
pep
xrange
catalesia
fuente
fuente
range
en Python 3.x esxrange
de Python 2.x. De hecho, Python 2.x'srange
fue eliminado.time
. Además de ser más fácil de usar y más difícil de equivocarse, y de repetir las pruebas por usted,timeit
se ocupa de todo tipo de cosas que no recordará, ni sabrá cómo cuidar (como deshabilitar el GC), y puede usar un reloj con miles de veces mejor resolución.range
sobrex%4 == 0
? ¿Por qué no solo probarlist(xrange())
vslist(range())
, para que haya tan poco trabajo extraño como sea posible? (Por ejemplo, ¿cómo sabe que 3.x no funcionax%4
más lentamente?) De hecho, ¿por qué está creando una granlist
cantidad de memoria, que implica una gran cantidad de asignación de memoria (que, además de ser lenta, también es increíblemente variable) ?iter(range)
Es redundante.list(range(..))
. Eso es equivalente al rango de python 2. O para decirlo de otra manera: a xrange se le ha cambiado el nombre de rango, porque es el mejor valor predeterminado; no era necesario tener ambos, hazlolist(range)
si realmente necesitas una lista. .Respuestas:
Algunas medidas de rendimiento, utilizando en
timeit
lugar de intentar hacerlo manualmentetime
.Primero, Apple 2.7.2 de 64 bits:
Ahora, python.org 3.3.0 de 64 bits:
Al parecer, 3.x
range
realidad es un poco más lento que 2.xxrange
. Y laxrange
funció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:
Por lo tanto, construir el
list
toma 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
range
tiene exactamente el mismo tamaño que un 2.xxrange
, 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
for
bucle explícito en lugar del bucle C dentrodeque
?Entonces, casi tanto tiempo perdido en la
for
declaración como en el trabajo real de iterar elrange
.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 arange
, y el 2.xrange
es lo que se eliminó.Aquí hay alguna prueba de que el
range
objeto 3.3 es un descendiente directo delxrange
objeto 2.x (y no de larange
funció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
range
má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.fuente
range
. Elrange
objeto en 3.3 es un descendiente directo delxrange
objeto en 2.7, no de larange
función en 2.7. Es como preguntar mientrasitertools.imap
se eliminó a favor demap
. No hay respuesta, porque tal cosa no sucedió.range
rato sin hacer nada más.El rango de Python3 es el xrange de Python2. No hay necesidad de rodearlo. Para obtener una lista real en Python3, debe usar
list(range(...))
Si quieres algo que funcione con Python2 y Python3, prueba esto
fuente
range
yxrange
se comportará de manera diferente. No es suficiente hacer esto, también habría que asegurarse de no asumir nunca querange
está devolviendo una lista (como lo haría en Python 2).futurize
herramienta para convertir automáticamente su código fuente: python-future.org/…El
range
tipo de Python 3 funciona igual que el de Python 2xrange
. No estoy seguro de por qué está viendo una desaceleración, ya que el iterador devuelto por suxrange
función es exactamente lo que obtendría si iterararange
directamente.No puedo reproducir la desaceleración en mi sistema. Así es como lo probé:
Python 2, con
xrange
:Python 3, con
range
es un poco más rápido:Hace poco aprendí que el
range
tipo de Python 3 tiene algunas otras características interesantes, como el soporte para cortar: ¡range(10,100,2)[5:25:5]
esrange(20, 60, 10)
!fuente
xrange
tantas veces, ¿o se hace solo una vez?xrange
se no se elimina, simplemente cambió el nombre .range
, en lo que a mí respecta, es el tiempo constante__contains__
. Los novatos solían escribir300000 in xrange(1000000)
y eso hizo que iterara todoxrange
(o al menos el primer 30%), por lo que tuvimos que explicar por qué era una mala idea, a pesar de que se ve tan pitón. Ahora, es pitónico.Una forma de arreglar su código python2 es:
fuente
range = xrange
como está en el comentario de @John La Royxrange = range
...xrange de Python 2 es un generador e implementa un iterador, mientras que el rango es solo una función. En Python3 no sé por qué se dejó caer la xrange.
fuente
range()
es el equivalente de PY2xrange()
. Y así en PY3xrange()
es redundante.comp: ~ $ python Python 2.7.6 (predeterminado, 22 de junio de 2015, 17:58:13) [GCC 4.8.2] en linux2
5.656799077987671
5.579368829727173
21.54827117919922
22.014557123184204
Con timeit number = 1 param:
0.2245171070098877
0.10750913619995117
comp: ~ $ python3 Python 3.4.3 (predeterminado, 14 de octubre de 2015, 20:28:29) [GCC 4.8.4] en Linux
9.113872020003328
9.07014398300089
Con timeit number = 1,2,3,4 param funciona de forma rápida y lineal:
0.09329321900440846
0.18501482300052885
0.2703447980020428
0.36209142999723554
Entonces parece que si medimos 1 ciclo de ciclo de ejecución como timeit.timeit ("[x para x en el rango (1000000) si x% 4]", número = 1) (como realmente usamos en código real) python3 funciona lo suficientemente rápido, pero en bucles repetidos, python 2 xrange () gana en velocidad contra range () desde python 3.
fuente