2012-06-25 7 views
6

Estoy tratando de usar un generador con una clase de Python que funciona de manera similar a una lista vinculada.Rendimiento en la estructura de datos recursiva

Aquí es un ejemplo muy simple de lo que quiero decir:

class GeneratorTest(): 
    def __init__(self, list): 
     if list: 
      self.elem = list[0] 
      if list[1:]: 
       self.n = GeneratorTest(list[1:]) 
      else: 
       self.n = None 

    def __iter__(self): 
     return self 

    def next(self): 
     my_next = self 
     while my_next is not None: 
      yield my_next 
      my_next = my_next.n 

Por supuesto, esto es sólo un ejemplo, pero es suficiente para ilustrar el punto.

Ahora, yo estaba esperando a ser capaz de invocar algo como:

g = GeneratorTest([1,2,3,4,5]) 
for x in g: 
    print x 

y tienen la parada del ciclo cuando alcanzó el último valor, pero el bucle simplemente continúa sin cesar.

Soy bastante nuevo en generadores, así que estoy seguro de que es una premisa básica que me falta aquí.

¿El problema está relacionado con el hecho de que cedo el mismo objeto que crea el generador? Estoy seguro de que si tuviera un objeto con una lista de objetos GeneratorTest, podría devolver cada uno de estos objetos de manera bastante simple, pero creo que debería haber una manera de hacerlo funcionar sin un objeto "envoltorio".

¿Qué me falta aquí?

+0

'list' es el nombre de un builtin, por lo que lo está sombreando cuando lo usa como argumento para su método' __init__'. – MattH

+0

sí, sí, lo sé, este es solo un ejemplo que pirateé y no me molesté con los nombres. El código real es similar en lógica pero con nombres que tienen sentido y que no eclipsan a los builtins. ¡Gracias por señalar eso de todos modos! – pcalcao

+0

Es muy útil proporcionar buenos ejemplos: autocontenido y demostrativo. – MattH

Respuesta

4

El problema es que next (o, en Py3, __next__) no debe ser un generador; debe mantener su estado externamente, y return cada valor. El tuyo sigue devolviendo un generador nuevo cada vez, pero dado que Python no itera sobre ese generador, tu bucle nunca se ejecuta realmente. Esto puede significar que desea __iter__ para devolver algo que no sea self inicialmente (aunque lo que devuelve se requiere tener un __iter__ que devuelve uno mismo).

Pero la buena noticia es que los generadores existen precisamente para hacer un seguimiento de estas reglas para usted. Mueva su código actual next en __iter__ y todo funciona - Python hace itera sobre lo que __iter__ devuelve (como era de esperar).

+0

¡De hecho lo hace! Eso tiene mucho más sentido ahora. – pcalcao

Cuestiones relacionadas