Estaba jugueteando con los generadores de Python y la clase iterable, solo por diversión. Básicamente, quería probar algo de lo que nunca estuve tan seguro: que las clases en Pythons tienen una sobrecarga significativa y es mejor confiar en los métodos que implementan yield
en lugar de las clases que implementan un protocolo de iterador, si es posible.python - Sobrecarga en el bucle en una clase iterable
no pude encontrar una explicación satisfactoria sobre este tema en Google, por lo que decidí ponerlas a prueba en mi propio uso de estos dos guiones simples: func_iter.py
y class_iter.py
Aquí está func_iter.py
:
#!/usr/bin/env python
import time
x = 0
def create_generator(num):
mylist = range(num)
for i in mylist:
yield i
t = time.time()
gen = create_generator(100000)
for i in gen:
x = x + i
print "%.3f" % (time.time() - t)
Y aquí es class_iter.py
:
#!/usr/bin/env python
import time
x = 0
class Generator(object):
def __init__(self, num):
self.start = 0
self.end = num
def __iter__(self):
return self
def next(self):
if self.start == self.end:
raise StopIteration
else:
self.start = self.start + 1
return self.start
t = time.time()
gen = Generator(100000)
for i in gen:
x = x + i
print "%.3f" % (time.time() - t)
entonces me encontré con cada uno de ellos 10 veces usando Thi s en bash (por class_iter.py
, por ejemplo):
for i in {1..10}; do ./class_iter.py; done
Y aquí están los tiempos medios de funcionamiento para cada uno de ellos:
class_iter.py: 0.0864
func_iter.py: 0.0307
Ahora, mis preguntas son:
- Son mis métodos son correctos? ¿Es justa mi comparación?
- Si es así, ¿por qué la gran diferencia? ¿Por qué
class_iter.py
tomó casi tres veces más tiempo quefunc_iter.py
para ejecutarse? - Si no es así, ¿cómo puedo mejorar mis métodos o encontrar una mejor comparación?
EDIT: Como se sugirió Dacav, también intenté correr func_iter.py
usando xrange
en lugar de range
. Esto disminuye su tiempo de ejecución promedio a 0.0263 segundos.
No creo que eso sea lo que quería probar. Está comparando un generador con un generador aquí, no un generador con el protocolo del iterador. Sí, la clase todavía es iterable, pero (por ejemplo) no puede resumir su estado porque el estado es un generador que no es miembro de la clase. – agf
¡Confirmado! Todavía es más lento por quizás 0.002 segundos ~ ¿es seguro asumir que esta diferencia se debe al tiempo que lleva crear una instancia de la clase? – bow
@bow: sí, creación de instancias de clase + accediendo a la variable de instancia en '__iter__'. Si tiene curiosidad por ver qué ocurre exactamente detrás de escena, intente con el módulo 'dis'. – georg