对所有捕获的异常执行常见操作的 Pythonic 方式

Pythonic way of doing common actions for all catched exceptions

如果我有以下结构:

try:
    do_something_dangerous()
except Exception1:
    handle_exception1()
    handle_all_exceptions()
except Exception2:
    handle_exception2()
    handle_all_exceptions()
...

如果我不想在每个 except 子句中调用 handle_all_exceptions,那么调用 handle_all_exceptions 的最 Pythonic 方法是什么,因为我有很多这样的子句?也许有一种简单的方法可以确定异常是否发生在 finally 子句中?

我能想到的最简单的方法是嵌套 try 语句:

try:
   try:
        do_something_dangerous()
    except Exception1:
        handle_exception1()
        raise
    except Exception2:
        handle_exception2()
        raise
except Exception:
    handle_all_exceptions()

raise 重新引发异常。

另一种选择是捕获所有异常并进行自己的调度,而不是为此使用 try 语句:

try:
    do_something_dangerous()
except Exception as e:
    if isinstance(e, Exception1):
        handle_exception1()
    if isisntance(e, Exception2):
        handle_exception2()
    handle_all_exceptions()

我认为您还可以检查异常的类型。但是,我不知道这是不是最pythonic的方式:

编辑: 查看文档,似乎没有最pythonic的方法。如何处理函数 handle_all_exceptions() 中的不同类型的异常取决于您。 See the doc.

try:
    do_something_dangerous()
except Exception as e:
    handle_all_exceptions(e)

def handle_all_exceptions(e):
    if isinstance(e, Exception1):
        handle_exception1()
    elif isinstance(e, Exception2):
        handle_exception2()

由于您不想检查实例或类似物,这里是另一种可能的实现方式。虽然列表实现肯定不是很好,但它解决了没有嵌套 try 语句的问题。您也可以使用布尔语句或类似语句,但是使用列表,您仍然可以访问错误对象以进行进一步处理。

ex = []
try:
    do_something_dangerous()
except Exception1 as e:
    ex.append(e)
    handle_exception1()
except Exception2 as e:
    ex.append(e)
    handle_exception2()
finally:
    if ex: handle_all_exceptions(ex)

您可以先定义一个映射关联处理函数与相应的异常:

err_handling = {
   Exception1: handle_exception1
   Exception2: handle_exception2
   # ...
}

然后您可以接受引发的异常作为 handle_all_exceptions 函数的参数,并使用处理映射和引发的异常类型为其添加特定处理。

def handle_all_exceptions(err):
    # common exception handling
    err_handling[type(err)]()

这样做你可以以一种简单的方式处理你的异常:

try:
    do_something_dangerous()
except Exception as err:
    handle_all_exceptions(err)

我在每个 except 子句中找到了一些没有 typeisinstance 和大量 raise 的棘手解决方案。也许它不是最 Pythonic,但至少很有趣:

try:
    do_something_dangerous()
except:
    try:
        raise
    except Exception1:
        handle_exception1()
    except Exception2:
        handle_exception2()
    handle_all_exceptions()