Python生成器,'coroutine'中的非吞咽异常

Eog*_*anM 12 python exception generator

我最近在Python生成器中遇到了一些令人惊讶的行为:

class YieldOne:
  def __iter__(self):
    try:
      yield 1
    except:
      print '*Excepted Successfully*'
      # raise

for i in YieldOne():
  raise Exception('test exception')
Run Code Online (Sandbox Code Playgroud)

这给出了输出:

*Excepted Successfully*
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
Exception: test exception
Run Code Online (Sandbox Code Playgroud)

我(令人愉快地)感到惊讶*Excepted Successfully*,因为这是我想要的,但也惊讶于Exception仍然传播到顶层.我期望必须使用(在此示例中注释)raise关键字来获取观察到的行为.

任何人都可以解释为什么这个功能的工作原理,以及为什么except生成器不会吞下异常?

这是Python中唯一except不会吞下异常的实例吗?

Joc*_*zel 14

您的代码没有按照您的想法执行.你不能在这样的协程中引发例外.你做的是捕捉GeneratorExit异常.看看使用不同的Exception时会发生什么:

class YieldOne:
  def __iter__(self):
    try:
      yield 1
    except RuntimeError:
        print "you won't see this"
    except GeneratorExit:
      print 'this is what you saw before'
      # raise

for i in YieldOne():
  raise RuntimeError
Run Code Online (Sandbox Code Playgroud)

由于这仍然是upvotes,这里是你如何在生成器中引发异常:

class YieldOne:
  def __iter__(self):
    try:
      yield 1
    except Exception as e:
      print "Got a", repr(e)
      yield 2
      # raise

gen = iter(YieldOne())

for row in gen:
    print row # we are at `yield 1`
    print gen.throw(Exception) # throw there and go to `yield 2` 
Run Code Online (Sandbox Code Playgroud)

查看文档generator.throw.


Kat*_*iel 6

编辑:THC4k说的是什么.

如果您确实想在生成器中引发任意异常,请使用以下throw方法:

>>> def Gen():
...     try:
...             yield 1
...     except Exception:
...             print "Excepted."
...
>>> foo = Gen()
>>> next(foo)
1
>>> foo.throw(Exception())
Excepted.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
Run Code Online (Sandbox Code Playgroud)

你会注意到你获得了StopIteration顶级水平.这些是由耗尽元素的发电机引起的; 它们通常被for循环吞噬,但在这种情况下,我们使生成器引发异常,因此循环不会注意到它们.