Обработка исключений в 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
Дополнительные источники:
