Исключения и ошибки в Python
- Понятие исключений и ошибок
- Инструкция try/except/else/finally
- Инструкция raise
- Инструкция assert
- Краткие итоги параграфа
- Вопросы и задания для самоконтроля
Понятие исключений и ошибок в Python
Любой, даже самый опытный программист, в ходе разработки программ допускает различного рода ошибки, приводящие к тому, что программа либо не работает вообще, либо работает, но выполняет вовсе не то, что задумывалось. Причинами ошибок могут быть как неправильное использование синтаксиса и пунктуации языка (синтаксические ошибки), так и неверное понимание логики программы (семантические ошибки, которые в Python принято называть исключениями). При этом, если первый тип ошибок легко обнаружить с помощью интерпретатора, то на устранение логических ошибок порой может потребоваться не один час, поскольку такие ошибки обнаруживаются уже непосредственно в ходе использования программы, проявляясь либо в виде сбоев в ее работе, либо в получении совершенно непредвиденных результатов (см. пример №1).
# Синтаксические ошибки обнаружить легко.
# Имя переменной начали с цифры.
# SyntaxError: invalid decimal literal
# 35_days = 35
# Строка должна содержать запись целого числа.
# ValueError: invalid literal for int() with base 10: 'три'
# num = int('три')
# Числа и строки складывать нельзя.
# TypeError: unsupported operand type(s) for +: 'int' and 'str'
# res = 5 + 'один'
# Логические ошибки всплывут потом.
# На первый взгляд все верно, и программа даже будет
# работать, но только до тех пор, пока пользователь
# не введет ноль или неприводимое к числу значение.
a = int(input('Введите число: '))
print(10/a)
Введите число: 0
ZeroDivisionError: division by zero
Пример №1. Синтаксические и логические ошибки в Python.
В примере мы показали лишь несколько видов исключений. На самом деле их намного больше. И очень важно знать о них, а также иметь инструменты для их обнаружения и обработки. Именно поэтому в стандартной библиотеке Python присутствует внушительный набор готовых классов, представляющих различные виды исключений и синтаксических ошибок. Все они перечислены в разделе Built-in exceptions, где также представлена и подробная иерархия имеющихся классов исключений. Что касается обработки ошибок, то для этого Python предоставляет ряд специальных инструкций, которые мы и будем рассматривать в данном параграфе.
Инструкция try/except в Python
Пожалуй, основной «рабочей лошадкой» по обработке исключений в Python является составная инструкция try/except/else/finally, которая имеет следующий общий формат:
# Сначала выполняется основной блок инструкций.
try:
<Основные инструкции>
# Запускается, если в блоке try возникло исключение Exception_1.
except Exception_1:
<Инструкции обработки исключения>
# Запускается, если возникло любое из перечисленных исключений.
except (Exception_2, Exception_3):
<Инструкции обработки исключений>
# Работаем с экземпляром Exception_4, как с err.
except Exception_4 as err:
<Инструкции обработки исключения>
# Запускается для всех видов исключений.
except:
<Инструкции обработки исключений>
# Запускается, если в блоке try не возникло исключений.
else:
<Дополнительные инструкции>
# Запускается в любом случае.
finally:
<Финальные инструкции>
Первыми выполняются инструкции основного блока try. При обнаружении в нем ошибок, интерпретатор пытается найти соответствующий возникшему исключению блок except и, в случае наличия такового, выполняет его инструкции. После того как исключение будет обработано, оно уничтожается, а программа пытается продолжить работу в штатном режиме. Если же среди имеющихся блоков except соответствия найдено не будет, исключение переадресуется инструкции try, стоящей выше в программе, или на верхний уровень процесса, что скорее всего вынудит интерпретатор аварийно завершить работу программы и вывести сообщение об ошибке по умолчанию. В случае отсутствия ошибок в блоке try интерпретатор пропускает все блоки except и начинает выполнять инструкции необязательного блока else, который разрешается использовать только при наличии хотя бы одного блока except. При этом стоит помнить, что при наличии ошибок в блоке try инструкции данного блока выполняться не будут. Что касается необязательного блока finally, то он используется для каких-либо завершающих операций, например, закрытия файлов или открытых соединений с сервером. Его инструкции выполняются всегда, вне зависимости от того, возникли исключения в каком-либо блоке, включая блок else, или нет (см. пример №2).
try:
# Здесь исключения могут возбудиться из-за
# ввода нечислового значения или нуля.
a = int(input('Введите число: '))
print('10/{} = {}'.format(a, 10/a))
# Если введено не целое число.
except ValueError:
print('Введите целое число!')
# Если введен ноль.
except ZeroDivisionError:
print('На ноль делить нельзя!')
# Выполнится только при отсутствии ошибок.
else:
print('Операция прошла успешно!')
# Выполняется в любом случае.
finally:
print('Для завершения нажмите «Enter»!')
# Чтобы окно консоли не закрылось.
input()
Введите число: 0
На ноль делить нельзя!
Для завершения нажмите «Enter»!
-------------------------------
Введите число: один
Введите целое число!
Для завершения нажмите «Enter»!
-------------------------------
Введите число: 20
10/20 = 0.5
Операция прошла успешно!
Для завершения нажмите «Enter»!
Пример №2. Инструкция try/except/else/finally в Python (часть 1).
Стоит заметить, что в отличие от блоков except блок finally не останавливает распространение исключений до вышестоящей инструкции try или до обработчика исключений по умолчанию, т.е. в случае возникновения ошибок инструкции, следующие за блоком finally в программе, выполняться не будут (см. пример №3).
# Внешняя инструкция try.
try:
# Внутреняя инструкция try.
try:
# Здесь исключения могут появиться из-за
# ввода нечислового значения или нуля.
a = int(input('Введите число: '))
print('10/{} = {}'.format(a, 10/a))
# Выполняется в любом случае.
finally:
print('Внутренний блок finally.')
# Выполняется при отсутствии ошибок
# во внутреннем блоке try.
print('Все ОК! Ошибок нет!')
# Если введено не целое число или ноль.
except (ValueError, ZeroDivisionError):
print('Неверный ввод!')
# Выполнится только при отсутствии ошибок.
else:
print('Операция прошла успешно!')
# Выполняется в любом случае.
finally:
print('Внешний блок finally.')
# Чтобы окно консоли не закрылось.
input()
Введите число: 7
10/7 = 1.4285714285714286
Внутренний блок finally.
Все ОК! Ошибок нет!
Операция прошла успешно!
Внешний блок finally.
------------------------
Введите число: 0
Внутренний блок finally.
Неверный ввод!
Внешний блок finally.
Пример №3. Инструкция try/except/else/finally в Python (часть 2).
Если необходимо перехватывать сразу все возможные исключения, разрешается использовать инструкцию except без указания классов исключений. Эта особенность может быть весьма удобна при разработке своих собственных обработчиков ошибок. Однако при использовании такого варианта могут перехватываться нежелательные системные исключения, не связанные с работой создаваемого программного кода, а также случайно может прерываться распространение исключений, предназначенных для других обработчиков. Данная проблема была частично решена в Python 3.0 за счет введения альтернативы в виде суперкласса Exception, представляющего все прикладные исключения, но игнорирующего исключения, связанные с завершением программы (см. пример №4).
# Основной блок try.
try:
# Здесь исключения могут возбудиться из-за
# ввода нечислового значения или нуля.
a = int(input('Введите число: '))
print('10/{} = {}'.format(a, 10/a))
# Выводим строковое представление исключения.
except Exception as err:
print(err)
# Выполнится только при отсутствии ошибок.
else:
print('Операция прошла успешно!')
# Выполняется в любом случае.
finally:
# Чтобы окно консоли не закрылось.
input()
Введите число: one
invalid literal for int() with base 10: 'one'
------------------------
Введите число: 0
division by zero
------------------------
Введите число: 10
10/10 = 1.0
Операция прошла успешно!
Пример №4. Инструкция try/except/else/finally в Python (часть 3).
В конце добавим, что помимо основного варианта использования try/except/else/finally инструкция try может быть использована и в варианте try/finally, т.е. без блоков обработки исключений except. Как не трудно догадаться, основной задачей такого варианта использования инструкции является выполнение заключительных операций после выполнения кода основного блока.
Инструкция raise в Python
В примерах выше мы полагались на то, что интерпретатор автоматически определит появление ошибок во время выполнения программного кода. Однако в Python присутствует возможность и явного возбуждения исключений с помощью инструкции raise. Все что от нас требуется, это указать через пробел имя класса или экземпляра возбуждаемого исключения. Также разрешается использовать пустую инструкцию, тогда будет повторно возбуждено самое последнее исключение (см. пример №5).
try:
# Возбудим исключение IndexError принудительно.
# Экземпляр исключения создается автоматически.
raise IndexError
# Обработаем его.
except IndexError:
print('Перехватили IndexError!')
try:
# Все тоже самое, но здесь создаем экземпляр сами.
raise IndexError()
# Обработаем его.
except IndexError:
print('Перехватили IndexError!')
# Вложенная инструкция try.
try:
# Возбудили последнее исключение еще раз.
raise
# Обработаем его.
except IndexError:
print('Перехватили IndexError!')
Перехватили IndexError!
Перехватили IndexError!
Перехватили IndexError!
Пример №5. Инструкция raise в Python (часть 1).
Инструкция raise может использоваться для явного возбуждения не только встроенных исключений, но и созданных пользователем. Пользовательские исключения представляют собой самые обычные классы, наследуемые от классов встроенных исключений, чаще всего от класса Exception (см. пример №6).
# Создаем свой класс исключений, который
# наследуется от встроенного Exception.
class OnlyAlpha(Exception):
# Переопределим строковое представление.
def __str__(self):
return 'Разрешены только буквы!'
# Определим функцию проверки строки на
# наличие сторонних небуквенных символов.
def check_for_alpha(s):
# Если присутствуют не только буквы.
if not s.isalpha():
# Возбуждаем экземпляр своего исключения.
raise OnlyAlpha()
# Проверим, как все работает.
try:
# Просим ввести строку.
s = input('Введите имя: ')
# Проверяем ввод.
check_for_alpha(s)
# Обрабатываем польз. исключение.
except OnlyAlpha as err:
# Строковое представление экз.
print(err)
print('Попробуйте еще раз!')
# Если все прошло гладко.
else:
# Выводим введенное имя.
print('Привет, {}!'.format(s))
# В любом случае дополняем сообщением.
finally:
print('Имя – это ваш ник и логин!')
Введите имя: okpython
Привет, okpython!
Имя – это ваш ник и логин!
--------------------------
Введите имя: okpython.net
Разрешены только буквы!
Попробуйте еще раз!
Имя – это ваш ник и логин!
Пример №6. Инструкция raise в Python (часть 2).
Стоит добавить, что инструкция raise может использоваться и в формате raise/from, который используется значительно реже, поэтому здесь мы его рассматривать не будем. Однако не поленитесь и самостоятельно посетите подраздел «The raise statement» раздела «Simple statements» официального справочника языка, где хотя бы бегло ознакомьтесь и с этим вариантом инструкции.
Инструкция assert в Python
Инструкция assert представляет собой компактный условный вариант инструкции raise, предназначенный в основном для возбуждения исключений на этапе отладки программы. В общем виде ее можно представить в формате assert condition[, message], где condition – это условие, при невыполнении которого (возвращается False) будет возбуждено встроенное исключение AssertionError, а также при необходимости выведено необязательное сообщение message (см. пример №7).
# Допустим мы пишем функцию для расчета среднего
# значения чисел переданного ей списка.
def avg(li):
len_li = len(li)
# Список не должен быть пустым.
assert len_li != 0, 'Список пуст!'
# Возвращаем среднее значение.
return round(sum(li)/len_li, 3)
try:
# Запускаем функцию.
res = avg([])
# Отлавливаем исключение для обработки.
except AssertionError as my_err:
print(my_err)
# Результат выводим, если все в порядке.
else:
print('Среднее значение: {}'.format(res))
Список пуст!
Пример №7. Инструкция assert в Python.
Важно не забывать, что инструкция assert главным образом предназначена для проверки соблюдения ограничений, накладываемых самим программистом, а не для перехвата настоящих ошибок, которые интерпретатор Python в состоянии обработать самостоятельно во время выполнения программы. Поэтому как правило инструкцию assert не используют для выявления таких проблем, как выход индекса за допустимые пределы, несоответствие типов или деление на ноль.
Краткие итоги параграфа
- Основной инструкцией для обработки исключений в Python является составная инструкция try/except/else/finally. Если в инструкциях обязательного блока try возникают ошибки, интерпретатор пытается перехватить и обработать их с помощью блоков except. В случае отсутствия соответствий исключение передается инструкции try, стоящей выше в программе, или на верхний уровень процесса. Необязательный блок else выполняется только при отсутствии ошибок, а необязательный блок finally выполняется всегда. При этом в отличие от блоков except блок finally не останавливает распространение исключений до вышестоящей инструкции try или до обработчика исключений по умолчанию, поэтому в случае возникновения ошибок инструкции, следующие за блоком finally в программе, выполняться не будут.
- В стандартной библиотеке Python присутствует внушительный набор готовых классов, представляющих различные виды исключений и синтаксических ошибок. Все они перечислены в разделе Built-in exceptions, где также представлена и подробная иерархия имеющихся классов исключений.
- Важно помнить, что при использовании блока except без указания класса перехватываемого исключения интерпретатор будет пытаться перехватить все имеющиеся виды встроенных исключений. Однако нужно быть осторожным при использовании такого варианта инструкции воизбежание перехвата нежелательных системных исключений, не связанных с работой создаваемого программного кода.
- Для явного возбуждения исключений в Python предназначена инструкция raise, которой необходимо через пробел передавать имя класса или экземпляра возбуждаемого исключения. Данная инструкция может использоваться для явного возбуждения не только встроенных исключений, но и созданных пользователем. Пользовательские исключения представляют собой самые обычные классы, наследуемые от классов встроенных исключений, чаще всего от класса Exception.
- Для возбуждения исключений на этапе отладки программы предназначена инструкция assert condition[, message], где condition – это условие, при невыполнении которого (возвращается False) будет возбуждено встроенное исключение AssertionError, а также при необходимости выведено необязательное сообщение message. Использовать инструкцию следует главным образом для проверки соблюдения ограничений, накладываемых самим программистом, а не для перехвата настоящих ошибок, которые могут быть спокойно перехвачены интерпретатором Python.
Вопросы и задания для самоконтроля
1. В каком случае выполняется код блока else составной инструкции try/except/else/finally? Показать решение.
Ответ. Инструкции необязательного блока else выполняются только при отсутствии исключений в коде основного блока try.
2. Что произойдет с программой в случае возбуждения исключения, если в ней не предусмотреть его обработку? Показать решение.
Ответ. В таком случае исключение будет передано обработчику предоставляемому интерпретатором по умолчанию. Этот обработчик выведет сообщение об ошибке и завершит программу.
3. Перечислите верные форматы использования инструкции try: try/except/else, try/else, try/finally, try/except/finally, try/else/finally. Показать решение.
Ответ. Блок else может использоваться только при наличии хотя бы одного блока except, следовательно варианты try/else и try/else/finally недопустимы.
4. В каком случае выполняется код блока finally? Показать решение.
Ответ. Необязательный блок finally выполняется всегда. При этом в отличие от блоков except блок finally не останавливает распространение исключений до вышестоящей инструкции try или до обработчика исключений по умолчанию, поэтому в случае возникновения ошибок инструкции, следующие за блоком finally в программе, выполняться не будут.
5. Присутствуют ли в коде условия ошибки? Проверьте свой ответ, запустив код на исполнение. Показать решение.
try: a = 5; b = 0 n = a/b exept Exeption as err: print('Ошибка: «{}».'.format(err)) else: print('a/b = {}'.format(n)) finally: print('Обработка завершена!')
try:
a = 5; b = 0
n = a/b
# Правильно писать except и Exception.
except Exception as err:
print('Ошибка: «{}».'.format(err))
else:
print('a/b = {}'.format(n))
finally:
print('Обработка завершена!')
Ошибка: «division by zero».
Обработка завершена!
6. Имеется ли в Python возможность создавать и возбуждать исключения вручную? Показать решение.
Ответ. Да, имеется. Для явного возбуждения исключений в Python предназначена инструкция raise, которой необходимо через пробел передавать имя класса или экземпляра возбуждаемого исключения. Данная инструкция может использоваться для явного возбуждения не только встроенных исключений, но и созданных пользователем. Пользовательские исключения представляют собой самые обычные классы, наследуемые от классов встроенных исключений, чаще всего от класса Exception.
7. Для чего служит инструкция assert? Показать решение.
Ответ. Для возбуждения исключений на этапе отладки программы предназначена инструкция assert condition[, message], где condition – это условие, при невыполнении которого (возвращается False) будет возбуждено встроенное исключение AssertionError, а также при необходимости выведено необязательное сообщение message. Использовать инструкцию следует главным образом для проверки соблюдения ограничений, накладываемых самим программистом, а не для перехвата настоящих ошибок, которые могут быть спокойно перехвачены интерпретатором Python.
8. Дополнительные тесты по теме расположены в разделе «Обработка исключений» нашего сборника тестов по основам Питона.
9. Дополнительные упражнения и задачи по теме расположены в разделе «Обработка исключений» нашего сборника задач и упражнений по языку программирования Python.
Быстрый переход к другим страницам
- Итерации и генераторы в Python
- Исключения и ошибки в Python
- Функции в Python
- К содержанию учебника