处理异常的首选方法是什么?
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")
如果我在编写一些代码时不确定某些事情,我会尝试再次阅读 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")