使用屈服的递归

2024-04-26 10:20:51 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有办法混合递归和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

我只想知道这是否可以递归地完成。


Tags: trueheredefit语句startnextyield
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)

是的,你可以这样做:

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

不过,一旦达到最大递归深度,就会出错。

从Python3.3开始,您将能够使用

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

如果只是递归地调用生成器函数而不在其上循环或yield from-调用它,那么所做的只是构建一个新的生成器,而不实际运行函数体或生成任何结果。

有关详细信息,请参见PEP 380

在某些情况下,对于生成器,最好使用堆栈而不是递归。应该可以使用堆栈和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'])

这不是一刀切的解决方案,但是对于某些生成器,用堆栈处理代替递归可能会得到一个很好的结果。

相关问题 更多 >