【问题标题】:What happens when a coroutine raises an exception?当协程引发异常时会发生什么?
【发布时间】:2013-03-12 21:00:16
【问题描述】:

我不确定下面这段代码到底发生了什么:

def coroutine():
    lst = []
    try:
        while True:
            item = (yield lst)
            if item == 3:
                raise ValueError
            print('append {}'.format(item))
            lst.append(item)
    except GeneratorExit:
        print('GeneratorExit')

crt = coroutine()

next(crt)
print(crt.send(1))
print(crt.send(2))

try:
    print(crt.send(3))
except ValueError:
    pass

print(crt.send(4))

这个输出:

append 1
[1]
append 2
[1, 2]

Traceback (most recent call last):
  File "D:\Documents and Settings\Brecht\Desktop\crt.py", line 25, in <module>
    print(crt.send(4))
StopIteration

当使用调试器单步执行代码时,在raise ValueError 上,执行跳转到except GeneratorExit:,但不执行此 except 子句的主体(不打印“GeneratorExit”)。为什么不呢?

除此之外,我不认为我可以在协程抛出异常后以任何方式恢复协程?有什么特别的理由不允许这样做吗?这至少在我的特定用例中很有用:)

【问题讨论】:

  • 它跳到那里但不执行它,因为它是ValueError?
  • @minitech doh,当然!

标签: python coroutine


【解决方案1】:

当您抛出异常时,代码流总是被中断。一旦您在其中抛出异常,您就无法恢复中断的生成器。

来自PEP 342 (Coroutines via Enhanced Generators)

next() 方法一样,send() 方法返回下一个值 由生成器迭代器产生,或引发StopIteration,如果 生成器正常退出,或者已经退出。如果发电机 引发未捕获的异常,它会传播到send() 的调用者。

至于调试器跳转到except 行:您只是抛出了一个异常,解释器正在测试该异常是否被该行捕获。因为它只会捕获GeneratorExit,所以生成器会在此时退出。

【讨论】:

  • 异常后能恢复协程会不会有什么坏处?
  • @BrechtMachiels 在哪里会继续?处于什么状态?
  • @BrechtMachiels:如果异常是由于转换错误(非整数字符串值上的int(),列表上的IndexError 等)并且分配没有采取怎么办地方?异常从不是可恢复的,这就是异常的用途。
  • @MartijnPieters 异常可用于控制流(例外情况),但我明白了。
  • @delnan:我的意思是,您无法恢复引发异常的块。 :-) 如果您忽略给定块中的异常,则该块的执行上下文消失且无法恢复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 2019-02-11
  • 2016-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多