Обработка исключений в Python

Конспект посвящён исключениям в Python и способам их обработки
Исключения
Исключения — ошибки, происходящие во время выполнения программы и не являющиеся безусловно фатальными.
В Python есть встроенные исключения, такие как TypeError, ValueError, ZeroDivisionError и т.д. Список всех можно посмотреть в документации, но посмотрим на некоторые:
-
TypeError— Возникает, когда операция или функция применяется к объекту неподходящего типа. -
ValueError— Возникает, когда операция или функция получает аргумент, который имеет правильный тип, но неподходящее значение. -
IndexError— Возникает, когда индекс коллекции выходит за диапазон допустимых значений. -
KeyError— Возникает, когда указан несуществующий ключ словаря. -
NameError— Возникает, когда имя переменной не найдено. -
FileNotFoundError— Возникает, когда файл не найден. -
ZeroDivisionError— Возникает, когда второй аргумент операции деления равен нулю. -
SyntaxError— Возникает, когда в исходном коде присутствуют синтаксические ошибки.
Обычно понятия “ошибки” и “исключения” отождествляют, но нужно понимать, что ошибка — критическое состояние, которое нельзя или нет смысла перехватывать (в большинстве случаев). Тем не менее, технически в Python все ошибки являются исключениями, поскольку наследуются от класса BaseException. При этом SyntaxError обработать нельзя, ведь она возникает ещё до выполнения программы.
Итого, фактически в языке Python все ошибки — исключения, но если исходить из определения, то SyntaxError (и некоторые другие) не являются таковыми.
Иерархия встроенных исключений выглядит так:
|
|
Обработка исключений
Базовый шаблон
Общая идея, заложенная в основу метода обработки исключений, такая: программный код, в котором теоретически может возникнуть ошибка, берётся под контроль. В случае выполнения такого кода и возникновении ошибки, создаётся объект исключения, содержащий описание ошибки, а сам код останавливается.
Для обработки исключения используется блочная конструкция try-except. После ключевого слова try размещается блок программного кода, который подозревается на предмет возможного возникновения ошибки. Этот код будем называть контролируемым. По завершении этого блока указывается ключевое слово except, после которого идет еще один блок программного кода, который называется кодом обработки исключения.
Таким образом, шаблон следующий:
|
|
Если при выполнении кода в блоке try ошибка не возникла, то код обработки исключения в блоке except выполняться не будет. Если при выполнении кода в блоке try возникла ошибка, то выполнение кода trу блока прекращается, и выполняется код обработки исключения в блоке except.
Допустим, если в следующем блоке num2 == 0 или вместо чисел передаются строки, то блок except будет выполнен. При этом оставшийся код также будет выполнен вне зависимости от того, произошла ошибка или нет:
|
|
|
|
try-except можно вкладывать один в другойОбработка по типам исключений
Более утонченная обработка исключений подразумевает более индивидуальный подход. Речь идет о том, чтобы обработка ошибок базировалась на типе или характере ошибки. Ключевое слово, определяющее тип ошибки, указывается после ключевого слова except соответствующего блока.
Шаблон таков:
|
|
Интерпретатор проходит по коду так: выполняются команды блока try, в случае возникновения исключения выполнение блока прекращается и начинается последовательный просмотр except блоков на предмет совпадения типа возникшей ошибки и типа ошибки, указанного после ключевого слова в except блоке. Как только совпадение найдено, выполняются команды соответствующего блока, после чего управление переходит к команде после конструкции try-except. Если же при переборе except блоков совпадение по типу ошибки не найдено, выполнение кода прекращается и появляется сообщение об ошибке.
|
|
except, то первыми нужно указывать наиболее конкретные в соответствии с иерархией, поскольку обработчик исключений ловит не только указанные типы исключений, но и их потомковВ случае выше перехватываются ошибки только двух перечисленных типов. Если исключение будет иного типа, оно поднимется по стеку, и выполнение программы остановится.
Если одним except блоком требуется перехватить ошибки нескольких типов, их можно перечислить в кортеже:
|
|
pass или эллипсис (...), равноценные отсутствию операции. В ходе исполнения данных операторов ничего не происходит, поэтому они могут использоваться в качестве заглушки в тех местах, где это синтаксически необходимо, например, в инструкциях, где тело является обязательным, таких как def, except, with и т.дОбщий шаблон
Помимо уже указанных блоков в конструкции try-except также используется необязательный блок else, который размещается после последнего except блока и выполняется только в том случае, если во время выполнения try блока исключений вызвано не было.
Ещё существует блок finally, который размещается после последнего except блока или после блока else, если таковой имеется. Он будет выполнен в любом случае, вне зависимости от того, возникло исключение или нет. Его можно использовать, например, при работе с файлами, которые в любом случае нужно закрывать.
finally может также использоваться без блоков except и else. В этом случае, если в блоке try возникает исключение, то сначала выполняется блок finally, а затем исключение поднимается по стеку.
Блок finally, находящийся внутри функции, выполняется до инструкции return. Но всё же return запоминает объект, на который ссылается, поэтому, если возвращаемая переменная переопределяется в блоке finally, return всё равно вернёт запомненное значение:
|
|
Таким образом, общий шаблон try-except будет выглядеть так:
|
|
Исключение как объект
Если требуется доступ к сгенерированному исключению как к объекту, то используется следующий синтаксис (нужно обязательно указать тип исключения):
|
|
|
|
Возбуждение исключений
Для ручного возбуждения исключений используется оператор raise. В качестве аргумента оператор raise использует экземпляр класса, унаследованного от Exception. Класс указывает на тип исключения, а аргумент, передаваемый конструктору этого исключения, обычно описывает подробности возникновения исключительной ситуации.
|
|
|
|
При создании объекта исключения в конструкторе можно указать подробности возникновения исключительной ситуации. Конструктор любого исключения принимает переменное количество аргументов.
Оператор raise имеет несколько форматов:
-
raise<class_instance> — указывается экземпляр класса возбуждаемого исключения с аргументами при необходимости:raise ValueError('Oпиcaниe исключения'). -
raise<class_name> — указывается только название класса исключения:raise ValueError # Эквивалентно: raise ValueError() -
raise<class_name_or_instance> from <exception_object> — сначала указывается экземпляр класса или просто название класса, а потом объект исключения, на основании которого создается новое исключение. В этом случае объект исходного исключения сохраняется в атрибуте__cause__. При обработке вложенных исключений эти данные используются для вывода информации не только о последнем исключении, но и о первоначальном исключении.
|
|
raise— повторно возбуждается и пробрасывается выше последнее перехваченное исключение.
|
|
Пользовательские исключения
В Python можно создавать собственные типы исключений. Такая практика позволяет увеличить гибкость процесса обработки ошибок в рамках той предметной области, для которой написана программа.
Для создания собственного типа исключения необходимо создать класс, являющийся наследником одного из уже существующих типов исключений. Самым верным вариантов будет Exception.
Следующий пример описывает новый тип исключения с именем NegativeAgeError, который является потомком класса Exception. Класс Exception содержит весь необходимый функционал, позволяющий работать с исключениями, поэтому в большинстве случаев достаточно создать пустой класс, который является потомком класса Exception.
|
|
Приведенный ниже код при вводе некорректных значений приводит к возбуждению соответствующих типов исключений: ValueError – при нечисловых значениях или NegativeAgeError – при отрицательных числовых значениях:
|
|
assert
Оператор assert позволяет писать проверки работоспособности кода. Эти проверки обычно называют утверждениями. Утверждения используются для того чтобы убедиться, остаются ли верными определенные условия во время разработки программы.
Если какое-либо из утверждений оказывается ложным, это означает, что в программе есть ошибка. Если все утверждения истинны, то в программе ошибок нет.
Оператор assert — встроенный оператор, используемый для проверки того, является ли заданное утверждение истинным или ложным. Если утверждение истинно, то ничего не происходит, и выполняется следующая строка кода. Если же утверждение ложно, оператор assert останавливает выполнение программы и подобно оператору raise возбуждает исключение AssertionError.
Синтаксис таков: assert <statement>, <message>, где
Пример:
|
|
assert — это средство отладки, а не механизм обработки исключений.Основной источник: https://stepik.org/course/82541
Дополнительные источники:
cloudtips