Конструкция try - except для обработки исключений
Допустим, нам нужно написать функцию, которая возвращает частное от деления двух чисел; и ноль, если деление не удалось.
Кажется легко, верно? Давайте напишем код:
def division(x, y): return x / y
И вызовем его
>>> print(division(1, 0)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in division ZeroDivisionError: division by zero
Ошибка деления на ноль. Или как говорят, возникло исключение. Исключения можно избежать, если, например, до операции деления выполнить проверку на 0:
def division(x, y): if y == 0: return 0 return x / y
А тогда ещё пример:
>>> print(division(1.5, 7 ** 512)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in division OverflowError: int too large to convert to float
Если первый аргумент - число с плавающей точкой, а второй - большое целое число, то Python, пытаясь преобразовать его в число с плавающей точкой, терпит неудачу.
Можно, конечно, добавить ещё проверок. Но есть более простой способ, а именно обработать исключение с помощью конструкции try - except:
def division(x, y): if y == 0: return 0 try: answer = x / y except OverflowError: answer = 0 return answer
Программа пытается выполнить код в блоке try. Если получается, то далее выполнится то, что после блока. В нашей функции это возврат переменной answer.
Если не получается, то выполнение внутри блока try прерывается, а затем интерпретатор смотрит, что за исключение произошло. Если оно (либо его родитель) есть в одном из списков except, то выполнится блок except. Иначе возникнет исключение, то самое, которое было в блоке try.
Можно убрать проверку на 0, написав вместо неё обработку исключения в отдельном блоке except (и таких блоков может быть сколько угодно):
def division(x, y): try: answer = x / y except OverflowError: answer = 0 except ZeroDivisionError: answer = 0 return answer
записав имена исключения через запятую (только потому, что обработка обоих из них у нас одинакова):
def division(x, y): try: answer = x / y except (OverflowError, ZeroDivisionError): answer = 0 return answer
или, поскольку OverflowError и ZeroDivisionError это подвид ArithmeticError, можно перехватить только его:
def division(x, y): try: answer = x / y except ArithmeticError: answer = 0 return answer
try - except - else
Инструкция else в блоке try - except выполнится только, если при выполнении блока try не было исключения:
def division(x, y): try: answer = x / y except ArithmeticError: answer = 0 else: print("Деление было выполнено штатно") return answer
finally
Инструкции в блоке finally блока try - except выполнятся при любом исходе блока try. Даже если возникнет не отловленное исключение, перед выдачей ошибки выполнится блок finally:
def division(x, y): try: answer = x / y except OverflowError: answer = 0 else: print("Деление было выполнено штатно") finally: print("Заходи в наш телеграм-канал (ссылка внизу)") return answer print(division(2, 1)) print() print(division(1.5, 7 ** 512)) print() print(division(1, 0))
И вывод данной программы:
Деление было выполнено штатно Заходи в наш телеграм-канал (ссылка внизу) 2.0 Заходи в наш телеграм-канал (ссылка внизу) 0 Заходи в наш телеграм-канал (ссылка внизу) Traceback (most recent call last): File "C:\Users\Дмитрий\PycharmProjects\pyplanet\functional.py", line 17, in <module> print(division(1, 0)) ^^^^^^^^^^^^^^ File "C:\Users\Дмитрий\PycharmProjects\pyplanet\functional.py", line 3, in division answer = x / y ~~^~~ ZeroDivisionError: division by zero
Обычно инструкция finally нужна для того, чтобы корректно освободить ресурсы: открытые файлы, дополнительные процессы или окна и т.д.
Полный список встроенных исключений можно узнать в нашем справочнике. Полезно знать, какие исключения могут возникать в каких ситуациях.