while循环中的GeneratorExit

13

我对在 while 循环中捕获 GeneratorExit 行为不是很清楚,请看我的代码:

# python 
Python 2.6.6 (r266:84292, Sep  4 2013, 07:46:00) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def func():
...     while True:
...         try:
...             yield 9
...         except GeneratorExit:
...             print "Need to do some clean up."
... 
>>> g = func()
>>> g.next()
9
>>> g.close()
Need to do some clean up.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: generator ignored GeneratorExit

当调用g.close()时,会出现GeneratorExit被捕获并打印"需要进行一些清理"的情况,但我不明白为什么会出现RuntimeError。


1
对于那些遇到这个问题的人,你可能会无意中执行 try: yield some_operation(foo); except: pass。你可能认为这将忽略 some_operation 中的错误,但实际上它也会忽略由你正在 yield 到的调用站点触发的早期退出 GeneratorExit!相反,尝试在 try-except 中执行 some_operation,并在该 try-except 之后进行 yield。或者处理一个更小范围的异常! - btown
3个回答

16

"当调用g.close()时,会出现生成器退出(GeneratorExit)被捕获的情况"

是的,当调用生成器的close()方法时,会引发生成器退出(GeneratorExit)异常。

请参阅以下文档:

https://docs.python.org/2/library/exceptions.html

该异常将导致运行时错误。

在循环内引发上述异常后,实际上已经处理,您会看到打印的错误消息。 但是,循环仍然继续,并且仍然尝试产生9。 这就是您看到运行时错误的原因。 因此,将异常处理移至循环外部即可解决问题。


但是如果我在 while 循环之外捕获 GeneratorExit,那么我就看不到 RuntimeError,似乎一切都正常工作。 - Eric
@Eric 增加了另一个说明。 - Jobs

9

在打印"Need to do some clean up."后添加一个return语句即可。这是首选的方式,特别是当你无法移除异常时。

while True:
    try:
        yield 9
     except GeneratorExit:
        print "Need to do some clean up."
        return

2

你在循环内捕获异常,因此即使它收到异常,仍会尝试在下一次迭代中 yield 值。

将异常处理移到循环外部。


感谢@karoly-horvath。 - Eric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接