МУНИЦИПАЛЬНОЕ АВТОНОМНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ДОПОЛНИТЕЛЬНОГО ОБРАЗОВАНИЯ
«ЦЕНТР ДЕТСКОГО ТЕХНИЧЕСКОГО ТВОРЧЕСТВА»
Методическая разработка
«Распространение исключений в Python»
к дополнительной общеобразовательной
общеразвивающей программе
технической направленности
«Программирование на Python»
Возраст детей: 10-17 лет
Автор: Костычев Вадим Александрович
г. Заречный Пензенской области
2026 г.
Данный материал предназначен для преподавателей информатики, программирования и студентов (учащихся), изучающих язык программирования Python. Он может быть использован как на лекциях, так и при проведении практических занятий или самостоятельной работе.
Цель: сформировать у учащихся понимание механизма распространения (проброса) исключений по стеку вызовов и научить проектировать обработку ошибок на разных уровнях вложенности функций и методов.
Задачи:
1. Объяснить, как исключение «поднимается» по цепочке вызовов при отсутствии обработки.
2. Показать, что обрабатывать исключение можно не только там, где оно возникло, но и на любом уровне выше по стеку вызовов.
3. Продемонстрировать, как наличие try-except на одном уровне останавливает распространение исключения.
4. Научить читать и интерпретировать трассировку (Traceback) для понимания пути исключения.
5. Развить навык проектирования грамотной стратегии обработки ошибок в многоуровневых программах.
Что происходит, когда исключение не обработано?
Когда в коде возникает исключение, Python немедленно прерывает выполнение текущей функции и начинает искать ближайший блок try-except, способный его обработать. Если такого блока нет в текущей функции, исключение «поднимается» к той функции, которая её вызвала — и так далее, пока не достигнет основного уровня программы. Этот процесс называется распространением исключения (exception propagation).
Пример:
def inner():
print("Начало inner")
1 / 0 # исключение здесь
print("Конец inner") # не выполнится
def outer():
print("Начало outer")
inner()
print("Конец outer") # не выполнится
outer()
Вывод:
Начало outer
Начало inner
ZeroDivisionError: division by zero
Исключение, возникшее в inner(), распространяется:
- сначала в outer() (потому что outer вызвала inner),
- затем в основную программу (потому что outer была вызвана из модуля).
Поскольку нигде нет try-except, программа аварийно завершается.
Как читать трассировку (Traceback)?
Сообщение об ошибке (Traceback) показывает путь исключения по стеку вызовов — снизу вверх:
Traceback (most recent call last):
File "...", line 10, in
outer()
File "...", line 7, in outer
inner()
File "...", line 3, in inner
1 / 0
ZeroDivisionError: division by zero
Чтение:
- Исключение произошло в строке 1 / 0 внутри функции inner.
- Эта функция была вызвана из outer (строка 7).
- А outer — из основного модуля (строка 10).
Это и есть цепочка распространения.
Обработка исключения на любом уровне стека
Вы можете перехватить исключение не в той функции, где оно возникло, а в любой вызывающей её функции.
Пример:
def inner():
print("inner: начало")
1 / 0 # исключение
print("inner: конец")
def middle():
print("middle: начало")
inner()
print("middle: конец")
def outer():
print("outer: начало")
try:
middle()
except ZeroDivisionError as e:
print(f"Обработано в outer: {e}")
print("outer: конец")
outer()
Вывод:
outer: начало
middle: начало
inner: начало
Обработано в outer: division by zero
outer: конец
Исключение возникло в inner, но было обработано в outer — через два уровня вложенности. При этом функции inner и middle аварийно завершились, и их «конец» не был выполнен. Это демонстрирует ключевой принцип: исключение распространяется вверх по стеку вызовов, пока не встретит подходящий except-блок.
Что происходит при наличии нескольких обработчиков?
Если try-except есть на нескольких уровнях, исключение будет обработано на самом первом (ближайшем к месту возникновения), и дальше оно не пойдёт.
Пример:
def inner():
try:
1 / 0
except ZeroDivisionError:
print("Обработано в inner")
def middle():
try:
inner()
except ZeroDivisionError:
print("Обработано в middle") # НЕ выполнится!
def outer():
try:
middle()
except ZeroDivisionError:
print("Обработано в outer") # НЕ выполнится!
outer()
Вывод:
Обработано в inner
После обработки в inner() исключение считается разрешённым, и его распространение прекращается. Блоки except в middle и outer даже не активируются.
Практическая стратегия обработки исключений
Где лучше обрабатывать исключения?
| Уровень | Когда уместно |
| Там, где возникло | Если вы можете локально восстановить работу (например, повторить запрос, использовать значение по умолчанию). |
| На более высоком уровне | Если ошибка требует глобальной реакции: завершить операцию, показать сообщение пользователю, записать в лог. |
| В корне программы | Для перехвата всех неожиданных ошибок и предотвращения аварийного завершения (часто используется в серверных приложениях). |
Важные нюансы
1. Исключение прерывает выполнение функции
Как только возникает исключение, вся оставшаяся часть функции игнорируется — даже если после 1/0 стоит print("done").
2. Распространение работает и для методов классов
То же самое происходит при вызове методов: исключение поднимается от метода к функции, которая его вызвала и так далее.
3. Можно «пробросить» исключение дальше
Иногда нужно обработать частично, но продолжить распространение:
try:
risky_operation()
except ValueError as e:
log_error(e) # делаем что-то полезное
raise # пробрасываем исключение дальше!
Ключевое слово raise без аргументов повторно вызывает текущее исключение.
Заключение
- Исключение распространяется вверх по стеку вызовов, пока не найдёт except-блок;
- Обрабатывать можно на любом уровне — не обязательно там, где оно возникло;
- Первый найденный подходящий except останавливает распространение;
- Функции, в которых произошло или прошло исключение, аварийно завершаются;
- Трассировка (Traceback) показывает полный путь исключения — читайте её снизу вверх;
- Проектируйте обработку исключений осознанно: на том уровне, где можно принять правильное решение.
Понимание распространения исключений — это ключ к написанию устойчивых, отлаживаемых и профессиональных программ. Теперь вы не просто «ловите ошибки», а управляете потоком управления в сложных системах.
Проверь себя
1. Что такое стек вызовов и как он связан с распространением исключений?
2. Если исключение возникло в функции A, вызванной из B, а B — из C, где можно его обработать?
3. Почему после обработки исключения в inner() не срабатывают except в middle() и outer()?
4. Как заставить исключение «пройти мимо» обработчика и продолжить распространение?
5. Что произойдёт с кодом после строки, вызвавшей исключение, если оно не обработано в этой функции?
6. Зачем использовать raise внутри блока except?
7. Как читать Traceback: сверху вниз или снизу вверх?