Исключения¶
Исключения возникают тогда, когда в программе возникает некоторая исключительная ситуация. Например, к чему приведёт попытка чтения несуществующего файла? Или если файл был случайно удалён, пока программа работала? Такие ситуации обрабатываются при помощи исключений.
Это касается и программ, содержащих недействительные команды. В этом случае Python поднимает руки и сообщает, что обнаружил ошибку.
Ошибки¶
Рассмотрим простой вызов функции print
. Что, если мы ошибочно напишем
print
как Print
? Обратите внимание на заглавную букву. В этом случае
Python поднимает синтаксическую ошибку.
>>> Print('Привет, Мир!')
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
Print('Привет, Мир!')
NameError: name 'Print' is not defined
>>> print('Привет, Мир!')
Привет, Мир!
Обратите внимание, что была поднята ошибка NameError
, а также указано место,
где была обнаружена ошибка. Так в данном случае действует обработчик ошибок.
Исключения¶
Попытаемся считать что-либо от пользователя. Нажмите Сtrl-D
(или
Ctrl+Z
в Windows) и посмотрите, что произойдёт.
>>> s = input('Введите что-нибудь --> ')
Введите что-нибудь -->
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
s = input('Введите что-нибудь --> ')
EOFError: EOF when reading a line
Python поднимает ошибку с именем EOFError
, что означает, что он обнаружил
символ конца файла (который вводится при помощи Ctrl-D
) там, где не
ожидал.
Обработка исключений¶
Обрабатывать исключения можно при помощи оператора try..except
[1]. При
этом все обычные команды помещаются внутрь try-блока, а все обработчики
исключений – в except-блок.
Пример: (сохраните как try_except.py
)
try:
text = input('Введите что-нибудь --> ')
except EOFError:
print('Ну зачем вы сделали мне EOF?')
except KeyboardInterrupt:
print('Вы отменили операцию.')
else:
print('Вы ввели {0}'.format(text))
Вывод:
$ python3 try_except.py
Введите что-нибудь --> # Нажмите ctrl-d
Ну зачем вы сделали мне EOF?
$ python3 try_except.py
Введите что-нибудь --> # Нажмите ctrl-c
Вы отменили операцию.
$ python3 try_except.py
Введите что-нибудь --> без ошибок
Вы ввели без ошибок
Как это работает:
Здесь мы поместили все команды, которые могут вызвать исключения/ошибки, внутрь блокаtry
, а затем поместили обработчики соответствующих ошибок/исключений в блокexcept
. Выражениеexcept
может обрабатывать как одиночную ошибку или исключение, так и список ошибок/исключений в скобках. Если не указано имя ошибки или исключения, обрабатываться будут все ошибки и исключения.
Помните, что для каждого выражения try
должно быть хотя бы одно
соответствующее выражение except
. Иначе какой смысл был бы в блоке try
?
Если ошибка или исключение не обработано, будет вызван обработчик Python по умолчанию, который останавливает выполнение программы и выводит на экран сообщение об ошибке. Выше мы уже видели это в действии.
Можно также добавить пункт else
к соответствующему блоку try..except
.
Этот пункт будет выполнен тогда, когда исключений не возникает.
В следующем примере мы увидим, как можно получить объект исключения для дальнейшей работы с ним.
Вызов исключения¶
Исключение можно поднять при помощи оператора raise
[2], передав ему
имя ошибки/исключения, а также объект исключения, который нужно выбросить.
Вызываемая ошибка или исключение должна быть классом, который прямо или непрямо
является производным от класса Exception
.
Пример: (сохраните как raising.py
)
class ShortInputException(Exception):
'''Пользовательский класс исключения.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
text = input('Введите что-нибудь --> ')
if len(text) < 3:
raise ShortInputException(len(text), 3)
# Здесь может происходить обычная работа
except EOFError:
print('Ну зачем вы сделали мне EOF?')
except ShortInputException as ex:
print('ShortInputException: Длина введённой строки -- {0}; \
ожидалось, как минимум, {1}'.format(ex.length, ex.atleast))
else:
print('Не было исключений.')
Вывод:
$ python3 raising.py
Введите что-нибудь --> а
ShortInputException: Длина введённой строки -- 1; ожидалось, как минимум, 3
$ python3 raising.py
Введите что-нибудь --> абв
Не было исключений.
Как это работает:
Здесь мы создаём наш собственный тип исключения. Этот новый тип исключения называется
ShortInputException
. Он содержит два поля:length
, хранящее длину введённого текста, иatleast
, указывающее, какую минимальную длину текста ожидала программа.В пункте
except
мы указываем класс ошибкиShortInputException
, который будет сохранён как[3] переменнаяex
, содержащая соответствующий объект ошибки/исключения. Это аналогично параметрам и аргументам при вызове функции. Внутри этого пунктаexcept
мы используем поляlength
иatleast
объекта исключения для вывода необходимых сообщений пользователю.
Try .. Finally¶
Представим, что в программе происходит чтение файла и необходимо убедиться, что
объект файла был корректно закрыт и что не возникло никакого исключения. Этого
можно достичь с применением блока finally
.
Сохраните как finally.py
:
import time
try:
f = open('poem.txt')
while True: # наш обычный способ читать файлы
line = f.readline()
if len(line) == 0:
break
print(line, end='')
time.sleep(2) # Пусть подождёт некоторое время
except KeyboardInterrupt:
print('!! Вы отменили чтение файла.')
finally:
f.close()
print('(Очистка: Закрытие файла)')
Вывод:
$ python3 finally.py
Программировать весело
Если работа скучна,
Чтобы придать ей весёлый тон -
!! Вы отменили чтение файла.
(Очистка: Закрытие файла)
Как это работает:
Здесь мы производим обычные операции чтения из файла, но в данном случае добавляем двухсекундный сон после вывода каждой строки при помощи функции
time.sleep
, чтобы программа выполнялась медленно (ведь Python очень быстр от природы). Во время выполнения программы нажмитеctrl-c
, чтобы прервать/отменить выполнение программы.Пронаблюдайте, как при этом выдаётся исключение
KeyboardInterrupt
, и программа выходит. Однако, прежде чем программа выйдет, выполняется пунктfinally
, и файловый объект будет всегда закрыт.
Оператор with¶
Типичной схемой является запрос некоторого ресурса в блоке try
с последующим
освобождением этого ресурса в блоке finally
. Для того, чтобы сделать это
более “чисто”, существует оператор with
[4]:
Сохраните как using_with.py
:
with open("poem.txt") as f:
for line in f:
print(line, end='')
Как это работает:
Вывод должен быть таким же, как и в предыдущем примере. Разница лишь в том, что здесь мы используем функцию
open
с операторомwith
– этим мы оставляем автоматическое закрытие файла под ответственностьwith open
.За кулисами происходит следующее. Существует некий протокол, используемый оператором
with
. Он считывает объект, возвращаемый операторомopen
. Назовём его в данном случае “thefile”.Перед запуском блока кода, содержащегося в нём, оператор
with
всегда вызывает функциюthefile.__enter__
, а также всегда вызываетthefile.__exit__
после завершения выполнения этого блока кода.Так что код, который мы бы написали в блоке
finally
, будет автоматически обработан методом__exit__
. Это избавляет нас от необходимости повторно в явном виде указывать операторыtry..finally
.Более обширное рассмотрение этой темы выходит за рамки настоящей книги, поэтому для более исчерпывающего объяснения см. PEP 343.
Резюме¶
Мы обсудили использование операторов try..except
и try..finally
. Мы
также увидели, как создавать наши собственные типы исключений и как их вызывать.
Далее мы ознакомимся со стандартной библиотекой Python.