更好的语法用于仅在发生异常时重新抛出异常?

3 投票
2 回答
680 浏览
提问于 2025-04-17 20:16

我发现自己在想要捕捉一个错误时,总是会先运行一些特定的代码,然后再把原来的错误抛出来:

try:
    error = False
    # do something that *might* raise an exception
except Exception:
    error = True
finally:
    # something I *always* want to run
    if error:
        raise

我使用这个标志是因为如果没有之前的错误直接调用 raise,就会出现一个 TypeError 错误。有没有更符合 Python 风格的方法来做到这一点,而不需要这个标志呢?

2 个回答

3

finally 这部分代码会始终执行,无论在 tryexcept 代码块中发生了什么,或者 except 代码块是否存在。

这两种写法都可以正常工作:

try:
    # do something that *might* raise an exception
finally:
    # something I *always* want to run

 

try:
    # do something that *might* raise an exception
except Exception:
    raise
finally:
    # something I *always* want to run
10

在异常处理器中重新抛出异常:

try:
    # do something that *might* raise an exception
except Exception:
    raise
finally:
    # something I *always* want to run

finally 代码块会始终执行,无论你是否重新抛出了异常。

根据文档

如果有 finally,它就指定了一个“清理”处理器。try 代码块会执行,包括任何 exceptelse 代码块。如果在这些代码块中发生了异常并且没有被处理,这个异常会暂时保存。然后执行 finally 代码块。如果有保存的异常,它会在 finally 代码块结束时被重新抛出。

注意,如果 finally 代码块使用了 breakreturn 语句,保存的异常会被丢弃

如果 finally 代码块执行了返回或跳出语句,保存的异常会被丢弃:

def f():
    try:
        1/0
    finally:
        return 42

>>> f()
42

但是如果你在 try 代码块中使用了 breakcontinuereturnfinally 代码块仍然会被执行:

当在 try...finally 语句的 try 代码块中执行 returnbreakcontinue 语句时,finally 代码块也会在“退出时”被执行。

注意,在 Python 2.5 之前,你甚至不能在同一个 try 语句中结合使用 exceptfinally 代码块;请参见PEP 341: 统一的 try/except/finally。那时,你需要嵌套 try 语句:

try:
    try:
        # some code that could raise an exception
    except SomeException:
        # exception handler
finally:
    # cleanup code, always executed

撰写回答