【问题标题】:try yield finally - did we raise an exception?最后尝试 yield - 我们是否引发了异常?
【发布时间】:2014-06-14 08:34:18
【问题描述】:

TL;DR

是否有可能在 finally 子句中找出​​是否存在未捕获的异常?

背景

我想迭代项目以对其进行一些相对昂贵的处理,这可能会中断并引发异常。所以我想保住我的位置。 但是保存状态也相当昂贵 - 所以我不想每次都这样做,只是在我屈服的代码中有异常时。

我在想象一些形状模糊的东西:

def get_things(my_iterator):
    for items in my_iterator:
        try:
            yield item
        finally:
            if something_went_wrong():  # magic oracle function for failure
                save_state(item)
        continue_normal_processing()

但我不知道这是否可能。值得注意的是,except Exception: 不会引发任何事情,因为异常不在此函数中。

【问题讨论】:

  • 你的意思是其他地方在这个生成器之外引发了一个异常?那么try:/finally: 不是解决这个问题的正确方法; try 这里没有任何内容。
  • yield 如何引发异常?如果在生成下一个项目时发生异常,那么循环不是已经引发了吗?另外,为什么不在这里使用except 而不是finally?
  • 究竟是什么引发了异常? my_iterator 是异常的来源吗?
  • 您应该将 TD;DR 部分作为第一句话发布,因为这会作为该问题的简短描述显示给回答者。

标签: python exception-handling yield finally


【解决方案1】:

这应该与您想要的相似:

class CatchingExceptionsIterator:
    def __init__(self, generator):
        self.generator = generator
        self.error = None
    def __enter__(self):
        return self
    def next(self):
        if self.error is None:
            return next(self.generator)
        else:
            error = self.error
            self.error = None
            return self.generator.throw(*error)
    __next__ = next
    def __exit__(self, ty, err, tb):
        if ty is not None:
            self.error = ty, err, tb
            return True
    def __iter__(self):
        return self


def f():
    for i in range(10):
        try:
            print("yield")
            yield i
            print("returnFomYield")
        except:
            import traceback
            traceback.print_exc()


c = CatchingExceptionsIterator(f())
for i in c:
    with c:
        print(i)
        if i == 5:
            nameerror

必须对其进行调整以适合确切的用例。
输出是:

yield
0
returnFomYield
yield
1
returnFomYield
yield
2
returnFomYield
yield
3
returnFomYield
yield
4
returnFomYield
yield
5
Traceback (most recent call last):
  File "withiteration.py", line 27, in f
    yield i
  File "withiteration.py", line 39, in <module>
    nameerror
NameError: name 'nameerror' is not defined
yield
6
returnFomYield
yield
7
returnFomYield
yield
8
returnFomYield
yield
9
returnFomYield

还会执行一个附加的 finally 子句。

是否有可能在 finally 子句中找出​​是否存在未捕获的异常?

为什么?你可以使用except。更详细地解释这一点。

【讨论】:

    【解决方案2】:

    ...看来我对except 的行为完全错了。

    def f():
        for i in range(10):
            try:
                yield i
            except Exception:
                print "Nope, this broke"
                raise
    
    
    for x in f():
        print x
        if x == 2:
            raise IndexError
    

    返回

    0
    1
    2
    Nope, this broke
    Traceback (most recent call last):
    ...
    IndexError
    

    【讨论】:

    • 我没想到会有这种行为。酷。
    • 为下一个对此感到困惑的人提供更多信息:在生成器的垃圾收集期间打印“不,这坏了”。
    • 不管怎样,我只是在 2.7.12 上运行了这个代码示例,我没有得到“不,这坏了”的打印。
    • @DanielStutzbach - 澄清一下,你是说这种行为只是因为f() 是generator 函数而发生的?
    • 在 python 3.8 中,它会在不处理的情况下引发 IndexError。
    猜你喜欢
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 1970-01-01
    • 1970-01-01
    • 2017-12-31
    • 2020-11-05
    • 1970-01-01
    相关资源
    最近更新 更多