Исключение в Python — объект-ошибка, который возникает во время выполнения программы (runtime) и нарушает её нормальный поток. Если исключение не перехватить, интерпретатор выведет трассировку Traceback — многострочное сообщение с типом ошибки и цепочкой вызовов — и аварийно завершит программу.
Обработка исключений в Python строится на четырёх блоках: try, except, else и finally. Оператор raise генерирует исключение явно — встроенное или пользовательское. В статье разберём синтаксис этих конструкций, иерархию встроенных типов, создание собственных классов исключений, логирование ошибок и главные антипаттерны, которых лучше избегать.
Не знаете, с чего ребёнку начать в IT?
Дайте попробовать разные направления: Python, веб-разработку и робототехнику

Когда интерпретатор встречает ошибку, он создаёт объект исключения и «поднимает» его по стеку вызовов — LIFO-структуре (Last In, First Out — последним вошёл, первым вышел): сначала в текущую функцию, затем в вызвавшую её, и так далее — до первого перехватчика. Если перехватчика нет, программа завершается и выводится Traceback.
Traceback читается снизу вверх: нижняя строка содержит тип исключения и описание ошибки, выше — цепочка вызовов от точки сбоя к стартовому коду. Пример: функция f1() вызывает f2(), в f2() происходит ошибка во время исполнения — TypeError. Traceback покажет f2 внизу, f1 выше. Причину ищите в самой нижней строке: именно там тип и сообщение.
Хотите освоить Python с нуля — на реальных проектах, а не сухой теории? На курсе «Программирование: Уверенный старт» школьники за 4 недели пишут Telegram-бота, создают веб-приложение и собирают устройство на Arduino (микроконтроллере) — всё онлайн, бесплатно. Узнайте подробнее на странице курса.

Чтобы правильно обрабатывать исключения в Python, нужно понять роль каждого блока конструкции. Единственный обязательный — try; к нему нужен хотя бы один except или finally. Остальные блоки добавляются по необходимости.
try:
# код, который может вызвать ошибку
except ValueError as e:
# перехват конкретного типа
else:
# только если ошибок не было
finally:
# выполняется при любом исходе
Разберём поведение каждого блока подробнее.
Блок try следит за кодом внутри: как только возникает нештатная ситуация, выполнение прерывается и управление переходит к первому подходящему except. Если ни один обработчик исключений не подошёл — ошибка всплывает выше по стеку.
Конструкция except ExceptionType перехватывает конкретный тип. Ключевое слово as e привязывает объект исключения к переменной — через неё доступно текстовое сообщение (str(e)) и дополнительные атрибуты. Несколько типов в одном блоке перечисляются в кортеже: except (ValueError, TypeError) as e.
Порядок блоков критичен: специфические обработчики ставятся раньше общих. Если написать except Exception до except ValueError, блок ValueError никогда не сработает — его «поглотит» более широкий.
try:
n = int(input(«Введите число: «))
result = 10 / n
print(result)
except ValueError:
print(«Нужно ввести целое число»)
except ZeroDivisionError:
print(«На ноль делить нельзя»)
Блок else выполняется только если в try не возникло ни одного исключения. Он разделяет «счастливый путь» и код ошибок: что делать при успехе и что при сбое — явно разнесено, без смешивания в одном блоке.
Блок finally выполняется всегда — при ошибке, успехе, повторной генерации исключения и даже при return или break внутри try. Главный сценарий — освобождение ресурсов: закрытие файлов, соединений с базой данных, сетевых сокетов.
f = open(«data.txt»)
try:
data = f.read()
finally:
f.close() # выполнится при любом исходе
Более лаконичная альтернатива при обработке исключительных ситуаций с ресурсами — контекстный менеджер with open(«data.txt») as f: он закрывает ресурс автоматически и не позволяет «забыть» вызов close().
В Python более 70 встроенных исключений, выстроенных в иерархию. Корень — BaseException. Перехватывать его напрямую не стоит: он включает SystemExit и KeyboardInterrupt — служебные сигналы завершения программы и нажатия Ctrl+C. Поглотив их, вы лишите программу возможности нормально завершиться.
Для пользовательского кода рекомендованная база — Exception. От неё наследуются все «программные» ошибки. Промежуточные классы группируют родственные типы:
Иерархия исключений определяет порядок блоков except: специфические перехватчики всегда раньше общих. Если написать except LookupError перед except IndexError, второй блок никогда не сработает.
| Тип исключения |
Когда возникает |
Пример триггера |
|---|---|---|
| ValueError | Тип верный, значение некорректно | int(«abc») |
| TypeError | Операция над несовместимыми типами | «1» + 1 |
| ZeroDivisionError | Деление на ноль | 10 / 0 |
| IndexError | Индекс за пределами списка | lst[99] при len=3 |
| KeyError | Ключ отсутствует в словаре | d[«missing»] |
| FileNotFoundError | Файл не найден | open(«ghost.txt») |
| AttributeError | Объект не имеет атрибута | None.split() |
| ImportError | Модуль не найден | import nonexistent |
Если разные ошибки требуют разной реакции — используйте несколько блоков except последовательно. Если реакция одинаковая — перечислите типы в кортеже:
try:
value = int(input(«Введите число: «))
result = 10 / value
except (ValueError, ZeroDivisionError) as e:
print(f»Ошибка ввода или деления: {e}»)
Частый антипаттерн — голый except: без указания типа. Он перехватывает всё, включая KeyboardInterrupt и SystemExit: программа не завершится по Ctrl+C, а реальные ошибки скроются за молчаливым обработчиком. Правильный вариант «поймать всё» — except Exception: он не трогает системные исключения и оставляет программе возможность нормально завершиться.
Простое правило: всегда указывайте тип в блоке except. Голый except: — антипаттерн без исключений.

Оператор raise позволяет генерировать исключение явно, не дожидаясь ошибки интерпретатора. Три основных режима:
def divide(a, b):
if b == 0:
Ребенок хочет изучать программирование? Пусть начнёт с реальных проектов
На курсе школьники создают Telegram-бота, сайт и веб-приложение
raise ZeroDivisionError(«Делитель не может быть нулём»)
return a / b
Re-raise применяется в паттерне «залогировать и передать выше»: сначала logging.error(e), затем голый raise. Вышестоящий обработчик получит полный Traceback — и запись в лог, и оригинальную цепочку вызовов.

Пользовательское исключение — обычный класс Python, унаследованный от Exception или одного из его подклассов. Наследование от классов исключений — единственный способ создать собственный тип. Минимальный синтаксис:
class NegativeValueError(Exception):
«»»Вызывается при передаче отрицательного значения.»»»
pass
Соглашения именования: суффикс Error или Exception; докстринг с описанием условий возникновения. Для передачи контекстной информации переопределите __init__:
class InsufficientFundsError(Exception):
def __init__(self, requested, available):
super().__init__(
f»Нужно {requested} ₽, доступно {available} ₽»
)
self.requested = requested
self.available = available
Преимущества: семантическая ясность и иерархическая обработка. Создайте базовый AppError, от него унаследуйте DatabaseError, ValidationError, NetworkError — и перехватывайте их как по отдельности, так и через общий базовый класс. Читаемость кода и удобство отладки при этом заметно растут.

Модуль logging из стандартной библиотеки Python — правильный инструмент для записи ошибок. В отличие от print, он сохраняет временну́ю метку, уровень важности и контекст; записи уходят в файл и не теряются при перезапуске программы.
import logging
logging.basicConfig(
filename=»app.log»,
level=logging.ERROR,
format=»%(asctime)s %(levelname)s %(message)s»
)
try:
result = 10 / 0
except ZeroDivisionError as e:
logging.error(«Ошибка деления: %s», e)
Модуль поддерживает пять уровней важности: DEBUG (детали отладки), INFO (ход работы), WARNING (предупреждение), ERROR (ошибка выполнения), CRITICAL (критический сбой). Используйте уровень, соответствующий серьёзности события — логирование исключений через logging.error даёт куда больше информации, чем голый print.
Для освобождения ресурсов применяйте контекстный менеджер with: он автоматически вызывает __exit__ и закрывает файл или соединение при любом исходе. Лаконичнее и надёжнее, чем паттерн try/finally + close() вручную.

| ❌ Антипаттерн |
✅ Правильно |
Последствие |
|---|---|---|
| except: без типа | except Exception | Перехватывает KeyboardInterrupt, блокирует Ctrl+C |
| except Exception: pass | logging.error(…) | Ошибка замалчивается, отладка невозможна |
| try/except в каждой функции | Обработка там, где есть контекст | Код засоряется, ошибки подавляются неосознанно |
Оператор pass в блоке except — молчаливое игнорирование ошибок: программа продолжает работу в неизвестном состоянии. Это затрудняет отладку и делает поведение кода непредсказуемым. Если не можете полностью восстановиться после сбоя — залогируйте и передайте исключение выше через голый raise.
Отказоустойчивый код в Python строится на принципеEAFP («Easier to Ask Forgiveness than Permission» — «проще просить прощения, чем разрешения»): при редких ошибках try/except производительнее предварительных проверок через if/else. Условие if выполняется каждый раз, блок except — только при фактическом исключении. Именно поэтому грамотная обработка исключений в Python считается нормой, а не оборонительной мерой.
Python исповедует принцип EAFP — «проще просить прощения, чем разрешения». try/except отделяет основную логику от кода ошибок и не смешивает их в одном потоке. При редких сбоях это производительнее: условие if проверяется при каждом выполнении, блок except активируется только при фактическом исключении.
Это заголовок трассировки Python. Трейсбек читается снизу вверх: нижняя строка — тип и сообщение ошибки, выше — цепочка вызовов от точки сбоя к стартовому коду. Причину ищите в самой нижней строке — не в первых.
Для одиночных ресурсов — файла или соединения с базой данных — предпочтительнее with: лаконичнее и надёжнее. finally нужен, когда требуется сложная очистка нескольких разнородных ресурсов или логика, выходящая за рамки протокола __enter__/__exit__.
Повторно генерирует перехваченное исключение, сохраняя оригинальный traceback. Применяется в паттерне «залогировать и передать выше»: сначала logging.error(e), затем голый raise — ошибка дойдёт до вышестоящего обработчика с полным контекстом.
Нет — это загромождает код и создаёт ложное ощущение безопасности. Исключение обрабатывают там, где есть контекст для осмысленного решения: показать сообщение, выбрать запасное значение, повторить запрос. В «транзитных» функциях лучше дать ошибке всплыть выше по стеку вызовов.
BaseException — корень всей иерархии, включая SystemExit и KeyboardInterrupt. Его перехват блокирует Ctrl+C и sys.exit() — программа не завершится по запросу пользователя или операционной системы. Используйте только Exception и его подклассы.
Унаследуйте класс от Exception и определите __init__ с нужными полями:
class InsufficientFundsError(Exception):
def __init__(self, requested, available):
super().__init__(f»Нужно {requested}, доступно {available}»)
Добавьте докстринг и следуйте соглашению с суффиксом Error в имени класса.
TypeError — операция применена к объекту несовместимого типа: например, сложение числа и строки (1 + «a»). ValueError — тип правильный, но значение некорректно: int(«abc») — строка передана верно, но преобразовать её в число невозможно. Первый — ошибка интерфейса, второй — ошибка данных.
Пусть ребёнок сделает первый IT-проект уже в этом месяце
Бесплатный онлайн-курс с понятной программой, поддержкой и проектами для портфолио