代码之家  ›  专栏  ›  技术社区  ›  EoghanM

Python生成器,“coroutine”中的非吞入异常

  •  12
  • EoghanM  · 技术社区  · 15 年前

    class YieldOne:
      def __iter__(self):
        try:
          yield 1
        except:
          print '*Excepted Successfully*'
          # raise
    
    for i in YieldOne():
      raise Exception('test exception')
    

    它给出了输出:

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

    我(愉快地)很惊讶 *Excepted Successfully* 被打印出来,因为这是我想要的,但是也很惊讶异常仍然被传播到最高层。我希望必须使用(在本例中注释的) raise 获取观察到的行为的关键字。

    有谁能解释一下为什么这个功能能像它那样工作,以及为什么 except

    这是Python中唯一一个 除了

    2 回复  |  直到 15 年前
        1
  •  14
  •   Jochen Ritzel    13 年前

    你的代码并不像你想的那样。在这样的协同过程中不能引发异常。你要做的是抓住 GeneratorExit 例外。查看使用其他异常时会发生什么情况:

    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
    

    由于这仍然会得到支持票,下面是如何在生成器中引发异常的:

    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` 
    

    参见文档 generator.throw .

        2
  •  6
  •   Katriel    15 年前

    编辑: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
    

    你会注意到你得到了 StopIteration 在最高层。这些由耗尽元件的发电机升高;它们通常被 for 但是在这种情况下,我们让生成器引发了一个异常,这样循环就不会注意到它们。