Исключения¶
Исключения возникают тогда, когда в программе возникает некоторая исключительная ситуация. Например, к чему приведёт попытка чтения несуществующего файла? Или если файл был случайно удалён, пока программа работала? Такие ситуации обрабатываются при помощи исключений.
Это касается и программ, содержащих недействительные команды. В этом случае Python поднимает руки и сообщает, что обнаружил ошибку.
Ошибки¶
Рассмотрим простой вызов функции print. Что, если мы ошибочно напишем print как Print? Обратите внимание на заглавную букву. В этом случае Python поднимает синтаксическую ошибку.
1 2 3 4 5 6 7 | |
Обратите внимание, что была поднята ошибка NameError, а также указано место, где была обнаружена ошибка. Так в данном случае действует обработчик ошибок.
Исключения¶
Попытаемся считать что-либо от пользователя. Нажмите Сtrl-D (или Ctrl+Z в Windows) и посмотрите, что произойдёт.
1 2 3 4 5 6 | |
Python поднимает ошибку с именем EOFError, что означает, что он обнаружил символ конца файла (который вводится при помощи Ctrl-D) там, где не ожидал.
Обработка исключений¶
Обрабатывать исключения можно при помощи оператора try..except1. При этом все обычные команды помещаются внутрь try-блока, а все обработчики исключений — в except-блок.
Пример: (сохраните как try_except.py)
1 2 3 4 5 6 7 8 | |
Вывод:
1 2 3 4 5 6 7 8 9 10 11 | |
Как это работает:
Здесь мы поместили все команды, которые могут вызвать исключения/ошибки, внутрь блока try, а затем поместили обработчики соответствующих ошибок/исключений в блок except. Выражение except может обрабатывать как одиночную ошибку или исключение, так и список ошибок/исключений в скобках. Если не указано имя ошибки или исключения, обрабатываться будут все ошибки и исключения.
Помните, что для каждого выражения try должно быть хотя бы одно соответствующее выражение except. Иначе какой смысл был бы в блоке try?
Если ошибка или исключение не обработано, будет вызван обработчик Python по умолчанию, который останавливает выполнение программы и выводит на экран сообщение об ошибке. Выше мы уже видели это в действии.
Можно также добавить пункт else к соответствующему блоку try..except. Этот пункт будет выполнен тогда, когда исключений не возникает.
В следующем примере мы увидим, как можно получить объект исключения для дальнейшей работы с ним.
Вызов исключения¶
Исключение можно поднять при помощи оператора raise2, передав ему имя ошибки/исключения, а также объект исключения, который нужно выбросить.
Вызываемая ошибка или исключение должна быть классом, который прямо или непрямо является производным от класса Exception.
Пример: (сохраните как raising.py)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Вывод:
1 2 3 4 5 6 7 | |
Как это работает:
Здесь мы создаём наш собственный тип исключения. Этот новый тип исключения называется ShortInputException. Он содержит два поля: length, хранящее длину введённого текста, и atleast, указывающее, какую минимальную длину текста ожидала программа.
В пункте except мы указываем класс ошибки ShortInputException, который будет сохранён как3 переменная ex, содержащая соответствующий объект ошибки/исключения. Это аналогично параметрам и аргументам при вызове функции. Внутри этого пункта except мы используем поля length и atleast объекта исключения для вывода необходимых сообщений пользователю.
Try .. Finally¶
Представим, что в программе происходит чтение файла и необходимо убедиться, что объект файла был корректно закрыт и что не возникло никакого исключения. Этого можно достичь с применением блока finally.
Сохраните как finally.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Вывод:
1 2 3 4 5 6 | |
Как это работает:
Здесь мы производим обычные операции чтения из файла, но в данном случае добавляем двухсекундный сон после вывода каждой строки при помощи функции time.sleep, чтобы программа выполнялась медленно (ведь Python очень быстр от природы). Во время выполнения программы нажмите ctrl-c, чтобы прервать/отменить выполнение программы.
Пронаблюдайте, как при этом выдаётся исключение KeyboardInterrupt, и программа выходит. Однако, прежде чем программа выйдет, выполняется пункт finally, и файловый объект будет всегда закрыт.
Оператор with¶
Типичной схемой является запрос некоторого ресурса в блоке try с последующим освобождением этого ресурса в блоке finally. Для того, чтобы сделать это более "чисто", существует оператор with4:
Сохраните как using_with.py:
1 2 3 | |
Как это работает:
Вывод должен быть таким же, как и в предыдущем примере. Разница лишь в том, что здесь мы используем функцию open с оператором with — этим мы оставляем автоматическое закрытие файла под ответственность with open.
За кулисами происходит следующее. Существует некий протокол, используемый оператором with. Он считывает объект, возвращаемый оператором open. Назовём его в данном случае "thefile".
Перед запуском блока кода, содержащегося в нём, оператор with всегда вызывает функцию thefile.__enter__, а также всегда вызывает thefile.__exit__ после завершения выполнения этого блока кода.
Так что код, который мы бы написали в блоке finally, будет автоматически обработан методом __exit__. Это избавляет нас от необходимости повторно в явном виде указывать операторы try..finally.
Более обширное рассмотрение этой темы выходит за рамки настоящей книги, поэтому для более исчерпывающего объяснения см. :pep:343.
Резюме¶
Мы обсудили использование операторов try..except и try..finally. Мы также увидели, как создавать наши собственные типы исключений и как их вызывать.
Далее мы ознакомимся со стандартной библиотекой Python.