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)