python中的'yield'关键字是如何工作的,尤其是当它带有递归时?



我正在使用python来平整嵌套列表,例如 [1,2,[3,4,[5,[[6,7]]]]],我想创建一个生成器,以便我可以用于循环在嵌套列表中一个一个一个一个逐一打印所有数字。但这只是我预期的不正常。

当我用"打印"替换"收益率"关键字时,数字会一一打印。但是,这样它不再是发电机。

以下内容无法正常工作:

from collections.abc import Iterable
def flatten(nested):
    for item in nested:
        if isinstance(item, Iterable):
            flatten(item)
        else:
            yield item
x = [1,2,[3,4,[5,[[6,7]]]]]
y = flatten(x)
for element in y:
    print(element)

但是,如果我像下面一样编写了代码,则在其中替换了yield print,数字将正确打印

from collections.abc import Iterable
def flatten(nested):
    for item in nested:
        if isinstance(item, Iterable):
            flatten(item)
        else:
            print(item)
x = [1,2,[3,4,[5,[[6,7]]]]]
y = flatten(x)

用"收益",如果我写的话:

x = [[1,2],[3,4,[5,[[6,7]]]]]
y = flatten(x)
y.__next__()

错误消息将为y.__next__() StopIteration

您永远不会从递归调用中返回或屈服。添加收益率,它应该起作用。

from collections.abc import Iterable
def flatten(nested):
    for item in nested:
        if isinstance(item, Iterable):
            yield from flatten(item) #change here.
        else:
            yield item
x = [1,2,[3,4,[5,[[6,7]]]]]
y = flatten(x)
for element in y:
    print(element)
#Output:
1
2
3
4
5
6
7

请注意,无论您使用的收益率还是回报,此问题也固有地存在于您的原始功能中。这就是为什么您应该在仅使用print时要小心的原因,并且在递归调用中没有返回,它可以掩盖一个事实,即在代码正常运行时,输出未正确捕获/使用。

这修复了您的代码:

from collections.abc import Iterable

def flatten(nested):
    for item in nested:
        if isinstance(item, Iterable):
            yield from flatten(item)
        else:
            yield item

x = [1, 2, [3, 4, [5, [[6, 7]]]]]
y = flatten(x)
for element in y:
    print(element)

这是有效的,因为您再次致电flatten,但算了忘记yield from(毕竟,新调用也返回发电机(

请注意,isinstance(item, Iterable)可能不是您想要的,因为它会破坏字符串。字符串是Iterable,但是在for循环中,从其返回的字符本身就是字符串。最好检查它是否是列表。

def flatten(nested):
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item

for element in flatten([1, 2, ['three', 4, [5, [[6, 7]]]]]):
    print(element)

最新更新