【问题标题】:Nested generator object context嵌套生成器对象上下文
【发布时间】:2017-09-22 13:43:11
【问题描述】:

今天我玩弄了嵌套生成器函数,发现了一个有趣的属性/行为,我无法向自己解释。

也许这与对 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 行,在 停止迭代

所以我的问题是:为什么生成器已经到了尽头?

【问题讨论】:

    标签: python generator


    【解决方案1】:

    generator 对象是一个全局对象;你永远不会创造一个新的。一旦迭代或关闭,它就会耗尽。

    它已关闭,因为您在函数中使用了yield from。当bar 生成器函数结束时,GeneratorExit 异常被传播到底层生成器(因此foo() 实例),它也被关闭。 bar() 结束,因为没有对该对象的引用,它被清理了。

    来自Yield expressions section

    当使用yield from <expr> 时,它将提供的表达式视为子迭代器。该子迭代器生成的所有值都直接传递给当前生成器方法的调用者。使用send() 传入的任何值以及使用throw() 传入的任何异常都会传递给底层迭代器(如果它具有适当的方法)。

    来自PEP-380 *Syntax for Delegating to a Subgenerator

    如果GeneratorExit异常被抛出到委托生成器,或者委托生成器的close()方法被调用,那么如果迭代器有close()方法,则调用它。

    详细来说,发生了什么,是这样的:

    • generator = foo() 创建一个新的生成器对象。
    • bar() 创建另一个。但是,除了堆栈之外,没有对此对象的引用。
    • next() 从堆栈中取出 bar() 生成器并将其转发一步。
    • next() 返回,并且没有对 bar() 生成器的引用,因此将其删除。
    • 删除生成器对象调用generator.close() method,在生成器中通过generator.throw()提升GeneratorExit
    • yield from 通过关闭该异常来将该异常传播到 foo() 生成器对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-18
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 2020-06-06
      • 2011-09-19
      • 1970-01-01
      • 2014-05-06
      相关资源
      最近更新 更多