【问题标题】:Explanation of generator.close() with exception handling带异常处理的 generator.close() 解释
【发布时间】:2020-05-25 00:20:15
【问题描述】:

我正在阅读关于generator.close() 的python 文档https://docs.python.org/3/reference/expressions.html

我对文档的翻译是:

##generator.close()

在生成器函数暂停的地方引发GeneratorExit

  1. 如果生成器函数正常退出:

1.1 已经关闭,
1.2 或引发GeneratorExit(通过不捕获异常),

close 返回给它的调用者。

  1. 如果生成器产生一个值,则会引发 RuntimeError

  2. 如果生成器引发任何其他异常,则会将其传播给调用者。

如果生成器由于异常或正常退出而已经退出,close() 不执行任何操作。


我不明白close() 行为与文档的对应关系。

>>> def echo(value=None):
...     print("Execution starts when 'next()' is called for the first time.")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> next(generator)
Execution starts when 'next()' is called for the first time.
>>> generator.close()
Don't forget to clean up when 'close()' is called.

哪条规则适用于 generator.close() ?我很困惑。

我的理解:

  1. generator.close() 引发 GeneratorExit 异常
  2. GeneratorExitexcept Exception as e: 捕获并继续循环
  3. value = (yield value) 执行
  4. 根据上述规则 2,将引发 RuntimeError

但似乎并非如此。

请告诉我里面发生了什么。

【问题讨论】:

    标签: python generator


    【解决方案1】:

    GeneratorExit 不是继承自 Exception,而是继承自更基本的 BaseException。因此,它不会被您的 except Exception 块捕获。

    所以你的假设 2 是错误的。生成器通过案例 1.3 优雅地退出,因为 GeneratorExit 没有停止。

    1. GeneratorExit 被抛出(yield value)
    2. try: except Exception as e: 检查当前异常是否是Exception 的子类。由于情况并非如此,因此它会放松。
    3. while True: 因当前异常而展开。
    4. try: finally: 展开,运行其finally: 块。这会导致显示消息。
    5. 生成器以当前异常退出,即GeneratorExit
    6. generator.close 检测并抑制 GeneratorExit

    【讨论】:

    • “优雅退出”是什么意思?
    • 这意味着它没有错误地退出,而不是由于内部遇到错误(情况 3)或未能及时退出(情况 2)而不正常地退出。
    • 正如您在问题中所写的,如果生成器确实提高或不停止GeneratorExit,那就是案例 1.1。而.close() 只是返回。
    • 啊,我明白了。我错误地将exits gracefullyis already closed,or raises GeneratorExit (by not catching the exception), 分为3 种情况,这是不正确的。现在我已经在问题中纠正了它。谢谢。
    • @kingusiu 如果生成器从未启动,.close 将根本不会运行生成器。在任何其他情况下,生成器只能yield 暂停,因此它可以在调用.close 时恢复。问题中的代码只完成了一半,显示了运行生成器后的行为,但不适合执行此操作的命令。
    猜你喜欢
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    相关资源
    最近更新 更多