python 中的“yield”关键字是如何真正起作用的,尤其是当它带有递归时?
Posted
技术标签:
【中文标题】python 中的“yield”关键字是如何真正起作用的,尤其是当它带有递归时?【英文标题】:How does the 'yield' keyword in python really work, especially when it comes with recursion? 【发布时间】:2019-12-07 11:40:30 【问题描述】:我正在使用 python 来展平嵌套列表,例如[1,2,[3,4,[5,[[6,7]]]]]
,我想创建一个生成器,以便我可以使用 for 循环在嵌套列表中一一打印所有数字。但它并没有像我预期的那样工作。
当我将 'yield' 关键字替换为 'print' 时,数字会一一打印出来。但是这样一来,它就不再是生成器了。
以下无法正常工作:
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)
如果我写了'yield':
x = [[1,2],[3,4,[5,[[6,7]]]]]
y = flatten(x)
y.__next__()
错误消息将是y.__next__() StopIteration
【问题讨论】:
【参考方案1】:这会修复您的代码:
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)
【讨论】:
你刚刚提醒了我python中的一个棘手点:字符是刺!因此,如果我在列表中包含一个字符串,它会将其展平为字符,但是字符仍然是刺痛的,因此它会不断变平......那是一场灾难。感谢您注意到我!【参考方案2】:您永远不会从递归调用中返回或让步。添加yield from,它应该可以工作。
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
请注意,这个问题也存在于您的原始函数中,无论您使用的是 yield 还是 return。这就是为什么在仅使用print
并且在递归调用中没有返回时应该小心的原因,它可以掩盖这样一个事实,即虽然代码运行正常,但输出没有被正确捕获/使用。
【讨论】:
以上是关于python 中的“yield”关键字是如何真正起作用的,尤其是当它带有递归时?的主要内容,如果未能解决你的问题,请参考以下文章