Recursión utilizando el rendimiento.

¿Hay alguna manera de mezclar la recursión y la statement de yield ? Por ejemplo, un generador de números infinitos (usando recursión) 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 dio start y el segundo dio start , luego el generador y luego se detuvo.

NOTA: Por favor, sé que puedes hacer esto usando un ciclo while:

 def infinity(start): while True: yield start start += 1 

Solo quiero saber si esto puede hacerse recursivamente.

Sí, usted puede hacer esto:

 def infinity(start): yield start for x in infinity(start + 1): yield x 

Sin embargo, esto se producirá un error una vez que se scope la profundidad máxima de recursión.

A partir de Python 3.3, podrás utilizar

 def infinity(start): yield start yield from infinity(start + 1) 

Si solo llama a la función de su generador de forma recursiva sin hacer un bucle o yield from ella, todo lo que debe hacer es construir un nuevo generador, sin ejecutar el cuerpo de la función ni ceder nada.

Ver PEP 380 para más detalles.

En algunos casos, podría ser preferible usar una stack en lugar de recursión para los generadores. Debería ser posible reescribir un método recursivo usando una stack y un bucle while.

Este es un ejemplo de un método recursivo que utiliza una callback y se puede reescribir utilizando la lógica de stack:

 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 en el que cada nodo tiene una matriz secundaria que puede contener nodos secundarios. A medida que se encuentra cada nodo, se emite la callback y se le pasa el nodo actual.

El método podría utilizarse de esta manera, imprimiendo algunas propiedades en cada nodo.

 def callback(node): print(node['id']) traverse_tree(callback) 

En su lugar, use una stack y escriba el método de recorrido como 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 de recorrido que originalmente, necesita invertir el orden de los niños porque el primer elemento secundario agregado a la stack será el último que se abrió).

Ahora puede obtener el mismo comportamiento que traverse_tree arriba, pero con un generador:

 for node in iternodes(): print(node['id']) 

Esta no es una solución de talla única, pero para algunos generadores puede obtener un buen resultado sustituyendo el procesamiento de stack por recursión.

Básicamente, solo necesita agregar un bucle for en el que necesite llamar a su función de forma recursiva . Esto se aplica para Python 2.7.