在Python __exit__块内重新抛出异常

20 投票
1 回答
9340 浏览
提问于 2025-04-17 18:42

在一个自定义光标类的__exit__块中,我想捕获一个异常,这样我就可以抛出一个更具体的异常。这样做的正确方法是什么呢?

class Cursor:
    def __enter__(self):
        ...

    def __exit__(self, ex_type, ex_val, tb):
        if ex_type == VagueThirdPartyError:
            # get new more specific error based on error code in ex_val and
            # return that one in its place.
            return False # ?
        else:
            return False

__exit__块中抛出具体的异常感觉有点像是个小技巧,但也许我想得太复杂了。

1 个回答

30

正确的做法是在 __exit__ 处理器里面抛出新的异常。

不过,你不应该抛出传入的那个异常;这样做是为了支持上下文管理器的链式调用。在这种情况下,你只需要从处理器返回一个“假值”(也就是表示“没有”或“失败”的值)。但是,抛出你自己定义的异常是完全可以的。

需要注意的是,最好使用身份测试 is 来验证传入异常的类型:

def __exit__(self, ex_type, ex_val, tb):
    if ex_type is VagueThirdPartyError:
        if ex_val.args[0] == 'foobar':
            raise SpecificException('Foobarred!')

        # Not raising a new exception, but surpressing the current one:
        if ex_val.args[0] == 'eggs-and-ham':
            # ignore this exception
            return True

        if ex_val.args[0] == 'baz':
            # re-raise this exception
            return False

    # No else required, the function exits and `None` is  returned

你也可以使用 issubclass(ex_type, VagueThirdPartyError) 来允许特定异常的子类。

撰写回答