Python 使用收益率的递归

Python 使用收益率的递归,python,python-2.7,recursion,yield,Python,Python 2.7,Recursion,Yield,有没有办法混合使用递归和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) 及

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

但是他们没有一个做了我想要的,第一个在产生
start
后停止,第二个产生
start
,然后发电机停止

注意:请注意,我知道您可以使用while循环执行此操作:

def infinity(start):
    while True:
        yield start
        start += 1
我只是想知道这是否可以递归完成。

是的,您可以这样做:

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)
如果你只是递归调用你的生成器函数,而没有在它上面循环,或者从中产生,那么你所做的就是构建一个新的生成器,而没有实际运行函数体或者产生任何结果


有关更多详细信息,请参阅。

在某些情况下,最好使用堆栈而不是递归生成程序。应该可以使用堆栈和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)
上述方法遍历一个节点树,其中每个节点都有一个子数组,该数组可能包含子节点。当遇到每个节点时,将发出回调并将当前节点传递给它

该方法可以这样使用,在每个节点上打印出一些属性

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)
(请注意,如果希望与最初的遍历顺序相同,则需要反转子对象的顺序,因为附加到堆栈的第一个子对象将是最后一个弹出的子对象。)

现在,您可以获得与上面的
遍历树
相同的行为,但使用生成器:

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

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

因此基本上,您只需要在处添加一个for循环,在那里您需要递归地调用您的函数。这适用于Python 2.7。

请参见[here][1],以获得我不久前提出的这个问题的好答案。[1] :注意:正确的方法是使用而不是滚动您自己的解决方案,基于循环或其他方法。@PetrViktorin这只是一个例子,生成无限数根本不是真正的问题,但从中获得的收益似乎仍然存在递归限制:(总会有一个递归的答案!Python2.7中的Yield不能真正用于递归,但通过手动管理堆栈,您可以获得相同的效果。虽然这个答案需要更多细节,但它实际上符合Sven Marnach的公认答案,请参阅他的第一段代码…什么是
b
?请不要离开cod电子版答案…一点澄清和解释将有助于把事情放在上下文中,更好地理解你在lprint(A):print(i)中对i的回答为什么不编辑答案以使其更清晰?您可以通过单击答案下方的小
edit
标记或单击来完成。此外,正如我所说,请尝试添加一些解释,说明这是如何以及为什么解决了问题
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)
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)