今天,我研究了嵌套生成器函数,发现了一个我无法向自己解释的有趣属性/行为。
也许这与对 yield from 的作用缺乏了解有关……。然而,现在问题来了:
def foo():
for iter in range(10):
yield iter
generator = foo()
def bar():
yield from generator
print(next(bar()), end=' ')
print(next(bar()), end=' ')
...
所以我排除的输出将是 0 1 ...。
但是,在第一次成功调用 next 之后,我得到: 追溯(最近一次通话): 文件“”,第 1 行,位于 停止迭代
所以我的问题是:为什么生成器已经到达终点?
请您参考如下方法:
generator对象是全局的;你永远不会创造一个新的。一旦遍历或关闭,它就用完了。
它已关闭,因为您使用了 yield from在一个函数中。当 bar生成器函数结束,GeneratorExit异常被传播到底层生成器(所以是 foo() 实例),它也被关闭。 bar()结束,因为没有对该对象的引用并且它已被清理。
When
yield from <expr>is used, it treats the supplied expression as a subiterator. All values produced by that subiterator are passed directly to the caller of the current generator’s methods. Any values passed in withsend()and any exceptions passed in withthrow()are passed to the underlying iterator if it has the appropriate methods.
来自PEP-380 *Syntax for Delegating to a Subgenerator :
If a
GeneratorExitexception is thrown into the delegating generator, or theclose()method of the delegating generator is called, then theclose()method of the iterator is called if it has one.
详细来说,发生了什么,是这样的:
-
generator = foo()创建一个新的生成器对象。 -
bar()创建另一个。但是,除了堆栈之外,没有对此对象的引用。 -
next()需要bar()从堆栈中取出生成器并将其转发一步。 -
next()返回,并且没有对bar()的引用生成器,所以它被删除了。 - 删除生成器对象会调用
generator.close()method , 提高GeneratorExit在生成器中,通过generator.throw(). -
yield from将该异常传播到foo()生成器对象也关闭它。
