Подтвердить что ты не робот

Рекурсия с использованием урожая

Есть ли способ смешивания рекурсии и оператора yield? Например, генератор бесконечного числа (с использованием рекурсии) будет выглядеть примерно так:

def infinity(start):
    yield start
    # recursion here ...

>>> it = infinity(1)
>>> next(it)
1
>>> next(it)
2

Я пробовал:

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

и

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

Но никто из них не сделал то, что я хочу, первый остановился после того, как он дал start, а второй дал start, затем генератор и затем остановился.

ПРИМЕЧАНИЕ: Пожалуйста, я знаю, что вы можете сделать это, используя цикл while:

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

Я просто хочу знать, можно ли это сделать рекурсивно.

4b9b3361

Ответ 1

Да, вы можете сделать это:

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

Это приведет к ошибке, если будет достигнута максимальная глубина рекурсии.

Начиная с Python 3.3, вы сможете использовать

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

Если вы просто вызываете свою генераторную функцию рекурсивно, не зацикливая на ней, или yield from -в ее, все, что вы делаете, это сборка нового генератора без фактического запуска тела функции или получения чего-либо.

Подробнее см. PEP 380.

Ответ 2

В некоторых случаях может быть предпочтительнее использовать стек вместо рекурсии для генераторов. Должна быть возможность переписать рекурсивный метод, используя стек и цикл while.

Вот пример рекурсивного метода, который использует обратный вызов и может быть переписан с использованием логики стека:

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)

Выше способ обходит дерево узлов, где каждый узел имеет children массив, который может содержать дочерние узлы. При обнаружении каждого узла выполняется обратный вызов, и текущий узел передается ему.

Метод можно использовать таким образом, распечатывая некоторые свойства на каждом узле.

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

Вместо этого используйте стек и напишите метод обхода в качестве генератора

# 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)

(Обратите внимание, что если вы хотите использовать тот же порядок обхода, что и вначале, вам нужно изменить порядок дочерних элементов, поскольку первый дочерний элемент, добавленный в стек, будет последним извлеченным.)

Теперь вы можете получить то же поведение, что и traverse_tree выше, но с генератором:

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

Это не универсальное решение, но для некоторых генераторов вы можете получить хороший результат, заменив обработку стека на рекурсию.

Ответ 3

def lprint(a):
    if isinstance(a, list):
        for i in a:
            yield from lprint(i)
    else:
        yield a

a = [[1, [2, 3], 4], [5, 6, [7, 8, [9]]]]
for i in lprint(b):
    print(i)

Ответ 4

Поэтому вам просто нужно добавить цикл for в , где вам нужно будет рекурсивно вызывать вашу функцию. Это относится к Python 2.7.