Мир Python: исключения — Python для продвинутых
В этом уроке вы узнаете о важном средстве языка, без которого крупная программа не может обойтись. Речь пойдет об исключениях. Что это такое, как ими пользоваться и как создавать собственные?
Исключительные ситуации или исключения (exceptions) – это ошибки, обнаруженные при исполнении. Например, к чему приведет попытка чтения несуществующего файла? Или если файл был случайно удален пока программа работала? Такие ситуации обрабатываются при помощи исключений.
Если же Python не может понять, как обойти сложившуюся ситуацию, то ему не остается ничего кроме как поднять руки и сообщить, что обнаружил ошибку. В общем, исключения необходимы, чтобы сообщать программисту об ошибках.
Простейший пример исключения — деление на ноль:
>>> 100 / 0 Traceback (most recent call last): File "", line 1, in 100 / 0 ZeroDivisionError: division by zero
В данном случае интерпретатор сообщил нам об исключении ZeroDivisionError – делении на ноль.
Traceback
В большой программе исключения часто возникают внутри. Чтобы упростить программисту понимание ошибки и причины такого поведения Python предлагает Traceback или в сленге – трэйс. Каждое исключение содержит краткую информацию, но при этом полную, информацию о месте появления ошибки. По трэйсу найти и исправить ошибку становится проще.
Рассмотрим такой пример:
Traceback (most recent call last): File "/home/username/Develop/test/app.py", line 862, in _handle return route.call(**args) File "/home/username/Develop/test/app.py", line 1729, in wrapper rv = callback(*a, **ka) File "/home/username/Develop/test/__init__.py", line 76, in wrapper body = callback(*args, **kwargs) File "/home/username/Develop/test/my_app.py", line 16, in index raise Exception('test exception')
В данном примере чётко видно, какой путь исполнения у программы. Смотрим снизу вверх и по шагам понимаем, как же мы докатились до такого исключения.
Рассмотрим какие ещё встречаются комментарии к исключениям:
>>> 2 + '1' Traceback (most recent call last): File "", line 1, in 2 + '1' TypeError: unsupported operand type(s) for +: 'int' and 'str'
В данном примере при попытке сложить целое число и строку мы получаем исключение TypeError. В описании сразу же становится ясно, что же мы не так написали.
>>> int('qwerty') Traceback (most recent call last): File "", line 1, in int('qwerty') ValueError: invalid literal for int() with base 10: 'qwerty'
Приведение строчки к целому числу приводит к исключению ValueError.
В трэйсе этих двух примеров можно прочесть, что в таком-то файле на такой-то строчке есть ошибки.
На этом список встроенных исключений не заканчивается, в следующем разделе рассмотрены основные исключения и причины их возникновения.
Иерархия исключений
Исключение, которое вы не увидите при выполнении кода – это BaseException – базовое исключение, от которого берут начало остальные.
В иерархии исключений две основные группы:
- Системные исключения и ошибки
- Обыкновенные исключения
Если обработку первых лучше не делать (если и делать, то надо четко понимать для чего), то обработку вторых целиком и полностью Python возлагает на плечи программиста.
К системным можно смело отнести:
- SystemExit – исключение, порождаемое функцией sys.exit при выходе из программы.
- KeyboardInterrupt – возникает при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
- GeneratorExit — возникает при вызове метода close объекта generator.
Остальные исключения – это «обыкновенные». Спектр уже готовых исключений велик.
Для Python2 иерархию исключений можно представить так:

Список исключений покрывает большой объем ситуаций и ошибок программиста. Если предупреждения (warning) только просят обратить внимание, то ошибки уже могут остановить исполнение программы.
В Python3 появились новые исключения и иерархия стала такова:

В целом заметно, что при создании Python3 добавлен блок новых исключений. Но даже этих почти 70 исключений не хватает при написании программ на языке Python.
Использование исключений
Мы рассмотрели что такое исключения, какие они бывают и как их анализировать. Но до сих пор явно не рассмотрели такую важную вещь, как их использование.
Начнем с обработки.
Обработка исключений
Давайте рассмотрим случай с делением на 0.
>>> a = 100 >>> b = 0 >>> c = a / b
Данный код приведет к исключению ZeroDivisionError. Чтобы этого не случилось, воспользуемся конструкцией try..except , например, так:
>>> try: . a = 100 . b = 0 . c = a / b . except ZeroDivisionError as e: . print(e) . division by zero
Если исполнить этот код, то на консоль будет выведена строка «integer division or modulo by zero«. Казалось бы, что толком ничего это нам не дало, ошибка все также есть. Однако в блок except можно поместить обработку.
Например, мы условились, что значение переменной c в случае ошибки деления равно -1. Тогда модифицируем код:
>>> try: . a = 100 . b = 0 . c = a / b . except ZeroDivisionError as e: . c = -1 >>> c -1
Перед тем как идти дальше, рассмотрим ещё одну возможность.
Пускай у нас файл с данными в файловой системе, и необходимо его прочитать. В этом случае сразу же всплывают несколько исключительных ситуаций, такие как: нет файла, файл битый, файл пустой (по заданию мы знаем, что в нём данные) и другие.
Используя исключения, можно вот так решить эту задачу:
try: filepath = 'test_file.txt' with open(filepath, 'r') as fio: result = fio.readlines() if not result: raise Exception("File is empty") except IOError as e: result = [] except Exception as e: result = [] print(e)
В данном вымышленном коде новый ход – перехват нескольких видов исключений. Когда исключение брошено, оно сравнивается сверху вниз с каждым типом, пока не найдено совпадение. Если совпадения нет, то исключение пойдет наверх по цепочке исполнения кода.
Если обработка для разных типов исключений одинакова, то уменьшить количество кода становится не проблемой:
try: your_code except (IOError, Exception) as e: print(e)
Вызов исключений
При работе с исключениями программист тратит большую часть времени на обработку, но при этом возникают ситуации, когда исключениями надо и бросать в других.
На сленге программистов «бросить исключение» означает написать код, который при исполнении будет инициировать исключительную ситуацию.
Например, функция, которая решает квадратное уравнение. Вы условились, что корни только вещественные, тогда в случае комплексных корней стоит бросить исключение.
Чтобы бросить исключение необходимо воспользоваться raise
raise IOError("текст исключения")
где IOError это класс исключения.
Если при обработке исключения вы желаете пробросить его ещё выше, то следует написать такой код:
try: your_code except Exception as e: raise
Собственные исключения
При написании собственных программ разумное желание добавить выразительности коду, а так же обратить внимание других программистов на особые исключительные ситуации. Для решения этой задачи стоит использовать собственные исключения.
В минимальном исполнении необходимо наследоваться от какого-нибудь класса в иерархии исключений. Например так:
class MyException(Exception): pass
Тогда можно бросить своё исключение:
raise MyException(Exception)
Легко заметить, мы создаем класс, а значит всё, что мы знаем о классах, справедливо и для исключений. Можно завести переменные и делать их обработку.
Как правило, исключения это очень маленькие классы. Они должны выполняться максимально быстро.
Дополнение: Полная форма try..except
Форма try. except не полная, полной же является try..except..else..finally .
Применение полной конструкции может заметно упростить код, а также сделать его более безопасным.
Представим, что в программе происходит чтение файла и необходимо убедиться, что объект файла был корректно закрыт и что не возникло никакого исключения. Этого можно достичь с применением блока finally.
Иными словами, finally выполняет блок инструкций в любом случае, было ли исключение, или нет. А инструкция else выполняется в том случае, если исключения не было.
В целом, использование полной формы таково:
try: исполяем какой-то код except Exception as e: обработка исключения else: код, который будет исполнен в случае, когда не возникает исключения finally: код, который гарантированно будет исполнен последним (всегда исполняется)
Выводы
В уроке рассмотрены вопросы связанные с исключениями:
- Что такое исключение
- Какие типы исключений присутствуют в языке
- Как обрабатывать исключения
- Как вызвать исключения
- Как создавать собственные исключения
![]()
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Об обучении на Хекслете
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар « Как самостоятельно учиться »
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Зачем нужна конструкция «finally» в Python
Часто при написании кода на Python возникает необходимость обработки исключений с помощью блока try. except . Это позволяет программе продолжать работу даже в случае возникновения ошибок. Например:
try: open_file() except FileNotFoundError: print("Файл не найден")
В этом примере код в блоке try пытается открыть файл. Если файл не найден и возникает ошибка FileNotFoundError , блок except обрабатывает эту ошибку и программа продолжает работу.
Однако, в некоторых случаях после выполнения блока try. except необходимо выполнить дополнительные действия, независимо от того, было ли исключение или нет. В этом случае на помощь приходит конструкция finally .
Рассмотрим следующий пример:
try: open_file() except FileNotFoundError: print("Файл не найден") finally: close_file()
В этом случае, независимо от того, была ли ошибка при открытии файла или нет, после выполнения блока try. except обязательно выполнится код в блоке finally . В данном случае — закроется файл. Это очень полезно, например, для освобождения ресурсов или закрытия открытых файлов или соединений с базами данных.
Таким образом, конструкция finally в Python используется для выполнения кода, который должен быть выполнен в любом случае после блока try. except , независимо от того, произошло исключение или нет.
Исключения в python. Конструкция try — except для обработки исключений

Исключения (exceptions) — ещё один тип данных в python. Исключения необходимы для того, чтобы сообщать программисту об ошибках.
Самый простейший пример исключения — деление на ноль:
Разберём это сообщение подробнее: интерпретатор нам сообщает о том, что он поймал исключение и напечатал информацию (Traceback (most recent call last)).
Далее имя файла (File «»). Имя пустое, потому что мы находимся в интерактивном режиме, строка в файле (line 1);
Выражение, в котором произошла ошибка (100 / 0).
Название исключения (ZeroDivisionError) и краткое описание исключения (division by zero).
Разумеется, возможны и другие исключения:
В этих двух примерах генерируются исключения TypeError и ValueError соответственно. Подсказки дают нам полную информацию о том, где порождено исключение, и с чем оно связано.
Рассмотрим иерархию встроенных в python исключений, хотя иногда вам могут встретиться и другие, так как программисты могут создавать собственные исключения. Данный список актуален для python 3.3, в более ранних версиях есть незначительные изменения.
- BaseException — базовое исключение, от которого берут начало все остальные.
- SystemExit — исключение, порождаемое функцией sys.exit при выходе из программы.
- KeyboardInterrupt — порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
- GeneratorExit — порождается при вызове метода close объекта generator.
- Exception — а вот тут уже заканчиваются полностью системные исключения (которые лучше не трогать) и начинаются обыкновенные, с которыми можно работать.
- StopIteration — порождается встроенной функцией next, если в итераторе больше нет элементов.
- ArithmeticError — арифметическая ошибка.
- FloatingPointError — порождается при неудачном выполнении операции с плавающей запятой. На практике встречается нечасто.
- OverflowError — возникает, когда результат арифметической операции слишком велик для представления. Не появляется при обычной работе с целыми числами (так как python поддерживает длинные числа), но может возникать в некоторых других случаях.
- ZeroDivisionError — деление на ноль.
- IndexError — индекс не входит в диапазон элементов.
- KeyError — несуществующий ключ (в словаре, множестве или другом объекте).
- UnboundLocalError — сделана ссылка на локальную переменную в функции, но переменная не определена ранее.
- BlockingIOError
- ChildProcessError — неудача при операции с дочерним процессом.
- ConnectionError — базовый класс для исключений, связанных с подключениями.
- BrokenPipeError
- ConnectionAbortedError
- ConnectionRefusedError
- ConnectionResetError
- IndentationError — неправильные отступы.
- TabError — смешивание в отступах табуляции и пробелов.
- UnicodeEncodeError — исключение, связанное с кодированием unicode.
- UnicodeDecodeError — исключение, связанное с декодированием unicode.
- UnicodeTranslateError — исключение, связанное с переводом unicode.
Теперь, зная, когда и при каких обстоятельствах могут возникнуть исключения, мы можем их обрабатывать. Для обработки исключений используется конструкция try — except.
Первый пример применения этой конструкции:
Ещё две инструкции, относящиеся к нашей проблеме, это finally и else. Finally выполняет блок инструкций в любом случае, было ли исключение, или нет (применима, когда нужно непременно что-то сделать, к примеру, закрыть файл). Инструкция else выполняется в том случае, если исключения не было.
Для вставки кода на Python в комментарий заключайте его в теги
Поймай меня, если сможешь: руководство по обработке исключений в Python

Люди, которые пишут код, часто воспринимают работу с исключениями как необходимое зло. Но освоение системы обработки исключений в Python способно повысить профессиональный уровень программиста, сделать его эффективнее. В этом материале я разберу следующие темы, изучение которых поможет всем желающим раскрыть потенциал Python через разумный подход к обработке исключений:
- Что такое обработка исключений?
- Разница между оператором if и обработкой исключений.
- Использование разделов else и finally блока try-except для организации правильного обращения с ошибками.
- Определение пользовательских исключений.
- Рекомендации по обработке исключений.
Что такое обработка исключений?
Обработка исключений — это процесс написания кода для перехвата и обработки ошибок или исключений, которые могут возникать при выполнении программы. Это позволяет разработчикам создавать надёжные программы, которые продолжают работать даже при возникновении неожиданных событий или ошибок. Без системы обработки исключений подобное обычно приводит к фатальным сбоям.
Когда возникают исключения — Python выполняет поиск подходящего обработчика исключений. После этого, если обработчик будет найден, выполняется его код, в котором предпринимаются уместные действия. Это может быть логирование данных, вывод сообщения, попытка восстановить работу программы после возникновения ошибки. В целом можно сказать, что обработка исключения помогает повысить надёжность Python-приложений, улучшает возможности по их поддержке, облегчает их отладку.
Различия между оператором if и обработкой исключений
Главные различия между оператором if и обработкой исключений в Python произрастают из их целей и сценариев использования.
Оператор if — это базовый строительный элемент структурного программирования. Этот оператор проверяет условие и выполняет различные блоки кода, основываясь на том, истинно проверяемое условие или ложно. Вот пример:
temperature = int(input("Please enter temperature in Fahrenheit: ")) if temperature > 100: print("Hot weather alert! Temperature exceeded 100°F.") elif temperature >= 70: print("Warm day ahead, enjoy sunny skies.") else: print("Bundle up for chilly temperatures.")Обработка исключений, с другой стороны, играет важную роль в написании надёжных и отказоустойчивых программ. Эта роль раскрывается через работу с неожиданными событиями и ошибками, которые могут возникать во время выполнения программы.
Исключения используются для подачи сигналов о проблемах и для выявления участков кода, которые нуждаются в улучшении, отладке, или в оснащении их дополнительными механизмами для проверки ошибок. Исключения позволяют Python достойно справляться с ситуациями, в которых возникают ошибки. В таких ситуациях исключения дают возможность продолжать выполнение скрипта вместо того, чтобы резко его останавливать.
Рассмотрим следующий код, демонстрирующий пример того, как можно реализовать обработку исключений и улучшить ситуацию с потенциальными отказами, связанными с делением на ноль:
# Определение функции, которая пытается поделить число на ноль def divide(x, y): result = x / y return result # Вызов функции divide с передачей ей x=5 и y=0 result = divide(5, 0) print(f"Result of dividing by : ")Traceback (most recent call last): File "", line 8, in ZeroDivisionError: division by zero attemptedПосле того, как было сгенерировано исключение, программа, не дойдя до инструкции print , сразу же прекращает выполняться.
Вышеописанное исключение можно обработать, обернув вызов функции divide в блок try-except :
# Определение функции, которая пытается поделить число на ноль def divide(x, y): result = x / y return result # Вызов функции divide с передачей ей x=5 и y=0 try: result = divide(5, 0) print(f"Result of dividing by : ") except ZeroDivisionError: print("Cannot divide by zero.")Cannot divide by zero.Сделав это, мы аккуратно обработали исключение ZeroDivisionError , предотвратили аварийное завершение остального кода из-за необработанного исключения.
Подробности о других встроенных Python-исключениях можно найти здесь.
Использование разделов else и finally блока try-except для организации правильного обращения с ошибками
При работе с исключениями в Python рекомендуется включать в состав блоков try-except и раздел else , и раздел finally . Раздел else позволяет программисту настроить действия, производимые в том случае, если при выполнении кода, который защищают от проблем, не было вызвано исключений. А раздел finally позволяет обеспечить обязательное выполнение неких заключительных операций, вроде освобождения ресурсов, независимо от факта возникновения исключений (вот и вот — полезные материалы об этом).
Например — рассмотрим ситуацию, когда нужно прочитать данные из файла и выполнить какие-то действия с этими данными. Если при чтении файла возникнет исключение — программист может решить, что надо залогировать ошибку и остановить выполнение дальнейших операций. Но в любом случае файл нужно правильно закрыть.
Использование разделов else и finally позволяет поступить именно так — обработать данные обычным образом в том случае, если исключений не возникло, либо обработать любые исключения, но, как бы ни развивались события, в итоге закрыть файл. Без этих разделов код страдал бы уязвимостями в виде утечки ресурсов или неполной обработки ошибок. В результате оказывается, что else и finally играют важнейшую роль в создании устойчивых к ошибкам и надёжных программ.
try: # Открытие файла в режиме чтения file = open("file.txt", "r") print("Successful opened the file") except FileNotFoundError: # Обработка ошибки, возникающей в том случае, если файл не найден print("File Not Found Error: No such file or directory") exit() except PermissionError: # Обработка ошибок, связанных с разрешением на доступ к файлу print("Permission Denied Error: Access is denied") else: # Всё хорошо - сделать что-то с данными, прочитанными из файла content = file.read().decode('utf-8') processed_data = process_content(content) # Прибираемся после себя даже в том случае, если выше возникло исключение finally: file.close()В этом примере мы сначала пытаемся открыть файл file.txt для чтения (в подобной ситуации можно использовать выражение with , которое гарантирует правильное автоматическое закрытие объекта файла после завершения работы). Если в процессе выполнения операций файлового ввода/вывода возникают ошибки FileNotFoundError или PermissionError — выполняются соответствующие разделы except . Здесь, ради простоты, мы лишь выводим на экран сообщения об ошибках и выходим из программы в том случае, если файл не найден.
В противном случае, если в блоке try исключений не возникло, мы продолжаем работу, обрабатывая содержимое файла в ветви else . И наконец — выполняется «уборка» — файл закрывается независимо от возникновения исключения. Это обеспечивает блок finally (подробности смотрите здесь).
Применяя структурированный подход к обработке исключений, напоминающий вышеописанный, можно поддерживать свой код в хорошо организованном состоянии и обеспечивать его читабельность. При этом код будет рассчитан на борьбу с потенциальными ошибками, которые могут возникнуть при взаимодействии с внешними системами или входными данными.
Определение пользовательских исключений
В Python можно определять пользовательские исключения путём создания подклассов встроенного класса Exception или любых других классов, являющихся прямыми наследниками Exception .
Для того чтобы определить собственное исключение — нужно создать новый класс, являющийся наследником одного из подходящих классов, и оснастить этот класс атрибутами, соответствующими нуждам программиста. Затем новый класс можно использовать в собственном коде, работая с ним так же, как работают со встроенными классами исключений.
Вот пример определения пользовательского исключения, названного InvalidEmailAddress :
class InvalidEmailAddress(ValueError): def __init__(self, message): super().__init__(message) self.msgfmt = messageЭто исключение является наследником ValueError . Его конструктор принимает необязательный аргумент message (по умолчанию он устанавливается в значение invalid email address ).
Вызвать это исключение можно в том случае, если в программе встретился адрес электронной почты, имеющий некорректный формат:
def send_email(address): if isinstance(address, str) == False: raise InvalidEmailAddress("Invalid email address") # Отправка электронного письмаТеперь, если функции send_email() будет передана строка, содержащая неправильно оформленный адрес, то, вместо сообщения стандартной ошибки TypeError , будет выдано настроенное заранее сообщение об ошибке, которое чётко указывает на возникшую проблему. Например, это может выглядеть так:
>>> send_email(None) Traceback (most recent call last): File "", line 1, in File "/path/to/project/main.py", line 8, in send_email raise InvalidEmailAddress("Invalid email address") InvalidEmailAddress: Invalid email addressРекомендации по обработке исключений
Вот несколько рекомендаций, относящихся к обработке ошибок в Python:
- Проектируйте код в расчёте на возможное возникновение ошибок. Заранее планируйте устройство кода с учётом возможных сбоев и проектируйте программы так, чтобы они могли бы достойно обрабатывать эти сбои. Это означает — предугадывать возможные пограничные случаи и реализовывать подходящие обработчики ошибок.
- Используйте содержательные сообщения об ошибках. Сделайте так, чтобы программа выводила бы, на экран, или в файл журнала, подробные сообщения об ошибках, которые помогут пользователям понять — что и почему пошло не так. Старайтесь не применять обобщённые сообщения об ошибках, наподобие Error occurred или Something bad happened . Вместо этого подумайте об удобстве пользователя и покажите сообщение, в котором будет дан совет по решению проблемы или будет приведена ссылка на документацию. Постарайтесь соблюсти баланс между выводом подробных сообщений и перегрузкой пользовательского интерфейса избыточными данными.
- Минимизируйте побочные эффекты. Постарайтесь свести к минимуму последствия сбойных операций, изолируя проблемные разделы кода посредством конструкции try-finally или try с использованием with . Сделайте так, чтобы после выполнения кода, было ли оно удачным или нет, обязательно выполнялись бы «очистительные» операции.
- Тщательно тестируйте код. Обеспечьте корректное поведение обработчиков ошибок в различных сценариях использования программы, подвергнув код всеобъемлющему тестированию.
- Регулярно выполняйте рефакторинг кода. Выполняйте рефакторинг фрагментов кода, подверженных ошибкам, чтобы улучшить их надёжность и производительность. Постарайтесь, чтобы ваша кодовая база была бы устроена по модульному принципу, чтобы её отдельные части слабо зависели бы друг от друга. Это позволяет независимым частям код самостоятельно эволюционировать, не оказывая негативного воздействия на другие его части.
- Логируйте важные события. Следите за интересными событиями своего приложения, записывая сведения о них в файл журнала или выводя в консоль. Это поможет вам выявлять проблемы на ранних стадиях их возникновения, не тратя время на длительный анализ большого количества неструктурированных логов.
Итоги
Написание кода обработки ошибок — это неотъемлемая часть индустрии разработки ПО, и, в частности — разработки на Python. Это позволяет разработчикам создавать более надёжные и стабильные программы. Следуя индустриальным стандартам и рекомендациям по обработке исключений, разработчик может сократить время, необходимое на отладку кода, способен обеспечить написание качественных программ и сделать так, чтобы пользователям было бы приятно работать с этими программами.
О, а приходите к нам работать?
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.