"yield from" 在递归函数中是如何工作的?

4

我正在编写一些Python代码,需要在递归函数中使用生成器。以下是我编写的一些代码,模拟了我尝试做的事情,这是第一次尝试。

def f():
    def f2(i):
        if i > 0:
            yield i
            f2(i - 1)
        
    yield f2(10)

for x in f():
    for y in x:
        print(y)

这个只会打印10,我找到了一个在线的yield from结构尝试了第二次。

def f():
    def f2(i):
        if i > 0:
            yield i
            yield from f2(i - 1)
        
    yield from f2(10)


for x in f():
    print(x)

这符合我的要求,但我不理解发生了什么,yield from在幕后做了什么,为什么我的第一次尝试不起作用?

在你的第一次尝试中,对f2()的递归调用是无意义的 - 它返回一个生成器,但你从未迭代它,因此其中的任何代码都不会被执行。 (因此只发生了一级递归,而不是你请求的10级。)yield from迭代生成器,并将其yield的值传递给下一个更高的级别。 - jasonharper
2个回答

4
你可以将yield from视为一个for循环,每次都会生成一个项:
for i in f(10):
    yield i

yield from f(10)for item in f(10): yield item的作用相同。换句话说,它从给定的迭代器(在这种情况下是另一个生成器)中yield项目。


这对于我的 f(10) 调用来说是有意义的,但我不确定这如何推广到我的递归 f2(i - 1) 调用。 - Mitch
这是相同的公式,你正在说在产出 i 之后,对于 f2(i-1) 产出的每个项目,将其向上返回链。 - nuric

1

yield from g()会在一个新的生成器g内递归,从该生成器的每个yield语句中产生结果。

因此,

def g1():
    yield from g2()

def g2()
    for i in range(10):
        yield i * 2

你可以将 g1 中的 yield from 视为展开了其中的 g2,扩展成了以下内容。
def g1():
    for i in range(10):
        yield i * 2

这不是因为你有作用域等内容,而是在g1中执行yield from g2()时,解释器会递归到g2并且每次产生值时都会返回,可能会递归到另一个生成器。

现在考虑这个生成器

def flatten(maybe_it): 
    try: 
        for i0 in maybe_it: 
            for i1 in flatten(i0): 
                yield i1 
    except TypeError: 
        yield maybe_it 

使用yield from可以将其重写为

def flatten(maybe_it): 
    try: 
        for i0 in maybe_it: 
            yield from flatten(i0): 
    except TypeError: 
        yield maybe_it

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接