处理异常的首选方法是什么?

What is preferable way to handle exceptions?

如果我在编写一些代码时不确定某些事情,我会尝试再次阅读 The Zen of Python。这次这些台词让我犹豫了。

Errors should never pass silently.
Unless explicitly silenced.

在当前代码中,我有一些函数可能如下所示:

def add_v_1(a, b):
    return a + b 

所有对他们的呼吁都像:

c = add_v_1(7, [])

此类代码的异常将冒泡并在上层捕获。

但应该是这样吗?

add_v_1 可以引发 TypeError 异常,我想从中恢复。 因此,可能的函数调用是:

try:
    c = add_v_1(7, [])
except TypeError:
    print "Incorrect types!"

但对于每次调用,我都应该进行异常处理。看起来很重。

所以,我可以做到:

def add_v_2(a, b):
    try:
        return a + b
    except TypeError:
        print "Incorrect types!"

呼叫将是:

c = add_v_2(7, [])

看起来更干净。

似乎所有这些方法都遵循 The Zen of Python 但其中哪一个是更好的选择?

输入:

def add_v_2(a, b):
    try:
        return a + b
    except Exception as e:
        print str(e)
c = add_v_2(7, [])
print (c)

输出:

unsupported operand type(s) for +: 'int' and 'list'
None

参考你的例子,是否应该在函数内部捕获异常是值得商榷的。这样做将从函数中 return None ,然后调用代码检查函数的 return 值,并将 None 视为错误。它有效地用错误检查代替了异常处理。前者通常更 Pythonic。

您应该问一下,捕获诸如尝试添加 2 种完全不同的数据类型之类的错误是否有意义。在这种情况下这样做似乎是一个编程错误,而不是您在正常执行期间所期望的那种事情。

你能做些什么来处理这样的错误?似乎没有任何有用的值可以在函数的预期输出范围内 returned... 除了 None 表示无法产生结果。但是调用代码 仍然 必须执行某种错误检查...所以它还不如只处理异常 - 至少它只需要处理一次。

但是这个例子是人为的,很难给出一揽子建议。在这种特殊情况下,出于上述原因,我会允许异常传播到调用代码并在那里进行处理。

当您能够从中恢复时,您应该处理异常。如果您尝试添加两个类型不兼容的值,则无法从中恢复(没有进一步的上下文)。

假设您编写了一个 IntegerWrapper class 并且您的函数 "add_v_2" 通常应该尝试连接两个值。

def add_v_2(a, b):
    try:
        return a + b
    except TypeError as e:
        if isinstance(a, IntegerWrapper):
            return str(a) + b
        else:
            print("I dont know how to handle this type: " + type(a).__name__)
            # reraise the error so the caller can handle it
            raise

这将尝试从 a 中恢复 "wrong type",但如果您知道如何从中恢复。如果它不知道(a 是另一种类型),它会重新引发异常,以便知道如何处理的人看到错误。

(当然,该实现包含错误,它并不意味着是 "good implementation")