Python 捕获多个异常

1 投票
4 回答
607 浏览
提问于 2025-04-18 13:36

我有一些代码,它会调用多个函数中的几个方法。这些方法可能会出现错误,每个方法可能会引发不同类型的错误。在我的主脚本中,我想记录这些错误,然后直接退出。所以,不管是什么类型的错误,都要记录下来,然后退出。

我的问题是:是列出所有可能出现的错误更好,还是直接捕获一个通用的错误更好?哪种方式更符合Python的风格呢?

例如:

try:
    some_stuff()
except (Exc1, Exc2, Exc3) as exc:
    loger.exception(exc)

或者这样:

try:
    some_stuff()
except Exception as exc:
    loger.exception(exc)

4 个回答

1

从Tim Peter的经验中学到一点:

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
...

明确的比隐含的要好。把可能出现的错误写出来,这样更符合“Python风格”。

1

在所有的编程语言和环境中,明确指定具体的异常是更好的做法。这样你就不会忽视一些你没有预料到的情况。除非你有非常非常好的理由,或者你的处理方式真的很通用,否则绝不要在正式代码中捕获Exception。一个合适的通用处理方式的例子是:记录日志、进行清理,然后重新抛出异常。

3

你打算在主代码中捕获异常、记录日志并终止程序的想法很好。

有些异常是可以接受的,并不意味着你需要把它们当成问题,比如 KeyboardInterrupt

可以采用这样的策略:

  • 首先,捕获所有你认为可以接受的异常,并用 pass 跳过它们。
  • 然后,捕获一般的 Exception,记录日志并终止程序。

代码可能看起来像这样:

try:
    some(stuff) # ...
# First, resolve expected exceptions
except KeyboardInterrupt:
    pass
# Finally, log unexpected ones
except Exception as exc:
    logger.exception(exc)
    return # time to terminate

什么时候显式捕获异常反而是失败

建议你显式捕获所有预期的异常,这在遇到意外异常时就不够用了。你计划捕获所有异常并记录到日志文件的做法听起来不错,这样可以为后续解决问题提供足够的信息。

想象一下,你有一个守护进程,它应该一直运行。在某些情况下,它可能会失败。

如果只期待显式的异常,可能会出现意外的异常,这时没有任何 expect 能够将其记录到日志文件中,堆栈跟踪信息会打印到标准输出并被遗忘,程序就会终止。

这就是一个很明显且合理的捕获异常的用例。

2

来自文档的内容:

因为使用 bare except: 会捕获所有的异常,包括 SystemExit、KeyboardInterrupt 和 GeneratorExit(这些并不是错误,通常不应该被用户代码捕获),所以直接使用 bare except: 几乎从来不是一个好主意。如果你需要捕获所有“正常”的错误,比如在一个运行回调的框架中,你可以捕获所有正常异常的基类 Exception。不过在 Python 2.x 中,第三方代码可能会抛出一些不继承于 Exception 的异常,所以在 Python 2.x 中,有些情况下你可能不得不使用 bare except:,然后手动重新抛出你不想捕获的异常。

一般来说,捕获明确的异常会更好。在 Python 2 中,如果你这样做,可能会导致一些异常仍然没有被捕获,尤其是当外部模块抛出一些不继承于异常的东西时。

通过捕获明确的异常,你可以处理你知道可能会发生的错误。如果你捕获所有异常,你的应用程序可能会做出一些意想不到的事情,而你可能会错误地处理这些情况。

另外,你真的想捕获有人按 Ctrl+C 来结束你的程序的情况吗?

撰写回答