¿Hay alguna forma de mezclar la recursividad y la yield
declaración? Por ejemplo, un generador de números infinitos (usando recursividad) sería algo como:
def infinity(start):
yield start
# recursion here ...
>>> it = infinity(1)
>>> next(it)
1
>>> next(it)
2
Lo intenté:
def infinity(start):
yield start
infinity(start + 1)
y
def infinity(start):
yield start
yield infinity(start + 1)
Pero ninguno de ellos hizo lo que yo quería, el primero se detuvo después de que cedió start
y el segundo cedió start
, luego el generador y luego se detuvo.
NOTA: Por favor, sé que puede hacer esto usando un bucle while:
def infinity(start):
while True:
yield start
start += 1
Solo quiero saber si esto se puede hacer de forma recursiva.
python
python-2.7
recursion
yield
juliomalegria
fuente
fuente
itertools.count
lugar de lanzar su propia solución, basada en bucles u otra.Respuestas:
Sí, usted puede hacer esto:
def infinity(start): yield start for x in infinity(start + 1): yield x
Sin embargo, esto generará un error una vez que se alcance la profundidad máxima de recursividad.
A partir de Python 3.3, podrá utilizar
def infinity(start): yield start yield from infinity(start + 1)
Si simplemente llama a su función de generador de forma recursiva sin hacer un bucle sobre ella o
yield from
-hacerla, todo lo que debe hacer es construir un nuevo generador, sin ejecutar el cuerpo de la función ni generar nada.Consulte PEP 380 para obtener más detalles.
fuente
yield from
que todavía hay un límite de recursividad :(En algunos casos, puede ser preferible utilizar una pila en lugar de la recursividad para los generadores. Debería ser posible reescribir un método recursivo usando una pila y un bucle while.
Aquí hay un ejemplo de un método recursivo que usa una devolución de llamada y se puede reescribir usando lógica de pila:
def traverse_tree(callback): # Get the root node from somewhere. root = get_root_node() def recurse(node): callback(node) for child in node.get('children', []): recurse(child) recurse(root)
El método anterior atraviesa un árbol de nodos donde cada nodo tiene una
children
matriz que puede contener nodos secundarios. A medida que se encuentra cada nodo, se emite la devolución de llamada y se le pasa el nodo actual.El método podría usarse de esta manera, imprimiendo alguna propiedad en cada nodo.
def callback(node): print(node['id']) traverse_tree(callback)
Use una pila en su lugar y escriba el método transversal como un generador
# A stack-based alternative to the traverse_tree method above. def iternodes(): stack = [get_root_node()] while stack: node = stack.pop() yield node for child in reversed(node.get('children', [])): stack.append(child)
(Tenga en cuenta que si desea el mismo orden transversal que originalmente, debe invertir el orden de los hijos porque el primer hijo agregado a la pila será el último en aparecer).
Ahora puede obtener el mismo comportamiento que el
traverse_tree
anterior, pero con un generador:for node in iternodes(): print(node['id'])
Esta no es una solución única para todos, pero para algunos generadores puede obtener un buen resultado sustituyendo el procesamiento de pila por la recursividad.
fuente
def lprint(a): if isinstance(a, list): for i in a: yield from lprint(i) else: yield a b = [[1, [2, 3], 4], [5, 6, [7, 8, [9]]]] for i in lprint(b): print(i)
fuente
b
? Trate de no dejar respuestas de solo código ... Una pequeña aclaración y explicación ayudarán a poner las cosas en contexto y comprender mejor su respuestaedit
etiqueta debajo de su respuesta o haciendo clic aquí . Además, como dije, intente agregar una pequeña explicación de cómo y por qué esto resuelve el problemaEntonces, básicamente, solo necesita agregar un bucle for en el lugar donde necesita llamar a su función de forma recursiva . Esto se aplica a Python 2.7.
fuente