TLDR:将异常处理程序移到实际发生异常的函数中:
def di(a, b):
try:
return a/b
except ZeroDivisionError:
print("Divide by 0 Error")
Python 中的函数定义会被执行,而这种执行可能会产生副作用——例如修改对象或引发异常。但是,根据定义,只有函数签名会立即运行;主体被存储并且仅在函数被调用时运行。
>>> def func(arg=print("default evaluated")):
... print("body evaluated")
...
default evaluated
>>> func
<function __main__.func(arg=None)>
>>> func()
body evaluated
当您在异常处理程序中定义函数时,此异常处理程序仅接收评估签名时引发的异常。例如,计算默认参数可能会引发ZeroDivisionError:
>>> def invalid_def(arg=10/0):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
这种情况下的异常处理程序很少是您想要的。有条件地定义一个函数可能很有用,例如如果NameError 表示依赖项不可用。
通常您希望处理源自函数体的异常。每当实际调用函数时,都会引发这些:
>>> def invalid_call():
... return 10 / 0
...
>>> invalid_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
>>> invalid_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
有两种方法可以处理此类异常:外部或内部。
-
外部处理需要在每个调用站点有一个异常处理程序。这更灵活,但需要样板文件,因为每次调用都需要一个异常处理程序。
>>> try:
... invalid_call()
... except ZeroDivisionError:
... print("suppressed an external error")
-
内部处理需要主体中的异常处理程序。这不太灵活,但不需要样板,因为一个异常处理程序涵盖所有情况。
>>> def valid_call():
... try:
... return 10 / 0
... except ZeroDivisionError:
... print("suppressed an internal error")
这两种方法都有效;选择哪个取决于您是否更需要可用性或可重用性。值得注意的是,将这两种方法结合起来并不少见:内部处理程序泛化异常,而外部处理程序只期望一般异常。
例如,在您的情况下,这将允许处理多个操作:
def div(a, b):
try:
return a / b
# convert operation-specific exception to general one
except ZeroDivisionError:
raise ValueError("Cannot divide by 0")
# may be another operation -- add, mul, sub, ...
operation = div
try:
operation(10, 0)
# only handle exception general to all operations
except ValueError as err:
print("Invalid values: %s" % err)