Rekurencja za pomocą yield
Czy jest jakiś sposób na zmieszanie rekurencji z yield
stwierdzeniem? Na przykład generator liczb nieskończonych (wykorzystujący rekurencję) byłby czymś w rodzaju:
def infinity(start):
yield start
# recursion here ...
>>> it = infinity(1)
>>> next(it)
1
>>> next(it)
2
Próbowałem:
def infinity(start):
yield start
infinity(start + 1)
I
def infinity(start):
yield start
yield infinity(start + 1)
Ale żaden z nich nie zrobił tego, co chciałem, pierwszy zatrzymał się po tym, jak dał start
, a drugi dał start
, potem generator i zatrzymał się.
Uwaga: proszę, wiem, że możesz to zrobić za pomocą pętli while:
def infinity(start):
while True:
yield start
start += 1
Chcę tylko wiedzieć, czy to można wykonać rekurencyjnie.
3 answers
Tak, możesz to zrobić:
def infinity(start):
yield start
for x in infinity(start + 1):
yield x
Spowoduje to błąd po osiągnięciu maksymalnej głębokości rekurencji.
Począwszy od Pythona 3.3, będziesz mógł używać
def infinity(start):
yield start
yield from infinity(start + 1)
Jeśli wywołasz funkcję generatora rekurencyjnie bez zapętlania jej lub yield from
- ing it, wszystko co robisz, to zbudujesz nowy generator, bez rzeczywistego uruchamiania ciała funkcji lub dawania czegokolwiek.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 22:26:37
W niektórych przypadkach lepiej byłoby użyć stosu zamiast rekurencji dla generatorów. Powinno być możliwe przepisanie metody rekurencyjnej przy użyciu stosu i pętli while.
Oto przykład metody rekurencyjnej, która wykorzystuje wywołanie zwrotne i może być przepisana za pomocą logiki stosu:
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)
Powyższa metoda przemierza drzewo węzłów, gdzie każdy węzeł ma tablicę children
, która może zawierać węzły potomne. Gdy każdy węzeł jest napotkany, wywołanie zwrotne jest wydawane i bieżący węzeł jest przekazywany za to.
Metoda może być użyta w ten sposób, wypisując pewne właściwości na każdym węźle.
def callback(node):
print(node['id'])
traverse_tree(callback)
Zamiast tego użyj stosu i napisz metodę traversal jako generator
# 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)
(zauważ, że jeśli chcesz mieć taką samą kolejność przechodzenia jak pierwotnie, musisz odwrócić kolejność dzieci, ponieważ pierwsze dziecko dołączone do stosu będzie ostatnim, które wyskoczy.)
Teraz możesz uzyskać takie samo zachowanie jak traverse_tree
powyżej, ale z generatorem:
for node in iternodes():
print(node['id'])
To nie jest uniwersalnym rozwiązaniem, ale dla niektórych generatorów można uzyskać ładny wynik zastępujący przetwarzanie stosu dla rekurencji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-18 13:19:51
Więc w zasadzie wystarczy dodać pętlę for w gdzie trzeba wywołać funkcję rekurencyjnie. Dotyczy to Pythona 2.7.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-28 21:45:38