A partir del código que has publicado, está claro que lo que se echa en falta es lo que un generador hace y cómo __iter__
y next
se supone que se comportan
Así que vamos a empezar con el protocolo de iteración. un objeto es iterable si devuelve un iterador cuando se llama a su método __iter__
, y un iterador es un objeto que tiene un método next
, que se puede llamar cero o más veces y debería elevar StopIteration
.
No es inusual que ciertos tipos de objetos sean sus propios iteradores (que tienen __iter__
return self
), pero esto generalmente se limita a objetos que de alguna manera representan una posición dentro de algo. Por ejemplo, el objeto incorporado file
es su propio iterador, porque los archivos tienen una posición de búsqueda intrínseca (que puede manipular con file.seek()
y file.tell()
). Otros objetos, que representan la totalidad de una colección, como list
, devuelven algo que no sean ellos mismos.
Por lo tanto, su árbol realmente suena más a este último que a lo anterior; No tiene un atributo de posición que represente en qué nodo está; son todos los nodos al mismo tiempo, por lo que probablemente no debe tener un método next()
; __iter__
necesita devolver algo más.
Lo que nos lleva a los generadores. Cuando una función normal contiene una declaración yield
, automáticamente no es una función en absoluto, es un generador. La diferencia es que cuando llamas a una función, su cuerpo se ejecuta (y posiblemente devuelve un valor). Cuando llamas a un generador, regresa de manera inmediata, sin ejecutar el cuerpo en absoluto; en cambio, obtienes un iterador! cuando itera sobre eso, se llama al cuerpo de la función; avanzando al siguiente yield
cada vez hasta que finalmente regrese.
lo tanto, poner todo junto,
class t:
def __init__(self):
self.l = []
self.a = 0
def __iter__(self):
# first, yield everthing every one of the child nodes would yield.
for child in self.l:
for item in child:
# the two for loops is because there's multiple children, and we need to iterate
# over each one.
yield item
# finally, yield self
yield self
Pero, puesto que lo que estamos haciendo es la iteración de una secuencia de iteradores (y también una cosa más, uno mismo), itertools.chain
como en la respuesta aceptada, de verdad Tiene mucho sentido.
no, no es suficiente. ¿Qué quieres ver? –