Антон Ларичев
Обработка исключений с помощью try/except в Python
Введение
В процессе выполнения программы неизбежно возникают ситуации, которые программист не предусмотрел заранее: пользователь ввёл строку вместо числа, файл оказался недоступен, ключ отсутствует в словаре. Для таких случаев в Python предусмотрен механизм исключений (exceptions) — специальных объектов, сигнализирующих о возникновении ошибки во время работы программы.
Конструкция try/except позволяет перехватывать исключения и реагировать на них корректно, не допуская аварийного завершения программы. В этой статье разберём, что такое исключения, как они возникают, и как грамотно их обрабатывать.
Что такое исключения и почему они возникают
Исключение — это объект в Python, который создаётся интерпретатором (или вашим кодом) в момент, когда выполнение программы встречает ситуацию, с которой не может справиться в штатном режиме.
Причины возникновения исключений можно разделить на несколько групп:
- Ошибки типов данных — попытка сложить строку с числом, передать неверный тип аргумента
- Ошибки доступа — обращение к несуществующему ключу словаря или индексу за пределами списка
- Ошибки ввода/вывода — файл не найден, нет прав на чтение
- Арифметические ошибки — деление на ноль
- Ошибки преобразования — невозможно превратить строку в число
Когда исключение возникает и не перехватывается, Python завершает программу и выводит трейсбек (traceback) — цепочку вызовов, приведших к ошибке. Например:
# Попытка преобразовать нечисловую строку в целое число
number = int("abc")
# ValueError: invalid literal for int() with base 10: 'abc'
Задача try/except — перехватить это исключение до того, как оно «убьёт» программу.
Базовый синтаксис try/except
Конструкция состоит из двух обязательных частей:
try:
# Блок кода, который может вызвать исключение
result = 10 / 0
except:
# Блок кода, который выполняется при возникновении исключения
print("Что-то пошло не так")
Логика работы следующая:
- Интерпретатор выполняет код в блоке
try - Если исключение не возникло — блок
exceptпропускается - Если исключение возникло — управление немедленно передаётся в блок
except
Дополнительно к try/except существуют ещё два необязательных блока:
try:
result = int(input("Введите число: "))
except ValueError:
print("Это не число!")
else:
# Выполняется только если исключения не было
print(f"Вы ввели: {result}")
finally:
# Выполняется всегда — и при ошибке, и без неё
print("Блок finally всегда выполняется")
else— выполняется только при отсутствии исключенияfinally— выполняется в любом случае, удобен для освобождения ресурсов (закрытие файлов, соединений)
Перехват конкретных типов исключений
Голый except без указания типа перехватывает абсолютно все исключения — это плохая практика (подробнее ниже). Правильный подход — указывать конкретный тип исключения.
ValueError
Возникает, когда операция получает аргумент правильного типа, но неподходящего значения:
user_input = "не число"
try:
number = int(user_input) # Попытка преобразовать строку в int
except ValueError:
print("Ошибка: введите корректное целое число")
TypeError
Возникает при операции с объектами несовместимых типов:
try:
result = "10" + 5 # Нельзя складывать строку и число напрямую
except TypeError:
print("Ошибка: несовместимые типы данных")
KeyError
Возникает при обращении к несуществующему ключу словаря:
user = {"name": "Алексей", "age": 25}
try:
email = user["email"] # Ключ "email" отсутствует в словаре
except KeyError:
print("Ошибка: ключ не найден в словаре")
email = None # Устанавливаем значение по умолчанию
IndexError
Возникает при обращении к индексу за пределами последовательности:
numbers = [1, 2, 3]
try:
value = numbers[10] # Индекс 10 не существует в списке из 3 элементов
except IndexError:
print("Ошибка: индекс выходит за пределы списка")
ZeroDivisionError
Возникает при попытке делить на ноль:
def safe_divide(a, b):
try:
return a / b # Потенциальное деление на ноль
except ZeroDivisionError:
print("Ошибка: деление на ноль")
return None
FileNotFoundError
Возникает при попытке открыть несуществующий файл:
try:
with open("data.txt", "r") as file:
content = file.read()
except FileNotFoundError:
print("Файл не найден. Создаём новый...")
content = ""
Если вы хотите детальнее изучить основы Python и научиться уверенно обрабатывать ошибки в реальных программах — приходите на наш большой курс Основы Python. На курсе 209 уроков и 34 упражнения, AI-тренажёры для практики 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.
Несколько блоков except
Одному блоку try можно сопоставить несколько блоков except — для обработки разных типов ошибок по-разному:
def parse_and_divide(data, index, divisor):
try:
value = data[index] # Может вызвать IndexError
result = int(value) # Может вызвать ValueError
return result / divisor # Может вызвать ZeroDivisionError
except IndexError:
print(f"Ошибка: индекс {index} выходит за границы списка")
except ValueError:
print(f"Ошибка: значение '{value}' нельзя преобразовать в число")
except ZeroDivisionError:
print("Ошибка: делитель равен нулю")
return None
Python проверяет блоки except последовательно сверху вниз и выполняет первый подходящий. После этого остальные блоки except пропускаются.
Несколько типов исключений можно также объединить в одном блоке, передав их как кортеж:
try:
value = int(input("Введите число: "))
result = 100 / value
except (ValueError, ZeroDivisionError):
# Обрабатываем оба случая одинаково
print("Некорректный ввод: введите ненулевое целое число")
Ключевое слово as — доступ к деталям исключения
Ключевое слово as позволяет получить объект исключения и изучить его атрибуты — в первую очередь сообщение об ошибке:
try:
number = int("abc")
except ValueError as error:
# error — это объект исключения с информацией об ошибке
print(f"Тип ошибки: {type(error).__name__}") # ValueError
print(f"Сообщение: {error}") # invalid literal for int() with base 10: 'abc'
Это особенно полезно при логировании:
import logging
def load_config(path):
try:
with open(path) as file:
return file.read()
except FileNotFoundError as error:
# Записываем подробности ошибки в лог
logging.error(f"Не удалось загрузить конфигурацию: {error}")
return None
Объект исключения хранит:
args— кортеж аргументов, переданных при создании исключения- строковое представление (через
str()) — текстовое сообщение об ошибке - у некоторых исключений есть специфические атрибуты (например,
errnoуOSError)
Голый except и почему это плохая практика
Голый except (bare except) — это блок except без указания типа исключения:
try:
result = risky_operation()
except: # Перехватывает АБСОЛЮТНО ВСЁ — это плохо
print("Что-то пошло не так")
Почему это проблема:
- Перехватывает системные исключения вроде
KeyboardInterrupt(Ctrl+C) иSystemExit— программу невозможно будет остановить штатным образом - Скрывает реальную причину ошибки — вы не знаете, что именно сломалось
- Затрудняет отладку — ошибки «исчезают» без следа
- Нарушает принцип явного указания намерений
Правильная альтернатива — перехватывать Exception, который захватывает все «обычные» исключения, но не системные:
try:
result = risky_operation()
except Exception as error:
# Exception не перехватывает KeyboardInterrupt и SystemExit
print(f"Произошла ошибка: {error}")
logging.exception("Необработанное исключение")
Ещё лучше — всегда указывать конкретные типы исключений, которые вы ожидаете.
Полный практический пример
Ниже — реалистичный пример функции для чтения данных из файла с комплексной обработкой ошибок:
def read_user_data(filepath, user_id):
"""
Читает данные пользователя из файла.
Возвращает словарь с данными или None при ошибке.
"""
try:
# Открываем файл для чтения
with open(filepath, "r", encoding="utf-8") as file:
import json
data = json.load(file) # Парсим JSON
users = data["users"] # Получаем список пользователей
user = users[user_id] # Берём пользователя по индексу
age = int(user["age"]) # Преобразуем возраст в число
return user
except FileNotFoundError:
print(f"Файл '{filepath}' не найден")
except json.JSONDecodeError as error:
print(f"Ошибка парсинга JSON: {error}")
except KeyError as error:
print(f"Ключ {error} отсутствует в данных")
except IndexError:
print(f"Пользователь с индексом {user_id} не существует")
except ValueError as error:
print(f"Некорректное значение: {error}")
finally:
# Этот блок выполнится всегда — удобно для логирования
print("Попытка чтения завершена")
return None
Частые ошибки
- Использование голого
exceptвместо конкретных типов исключений — скрывает реальные проблемы и затрудняет отладку - Перехват исключения без какой-либо реакции — «проглатывание» ошибок делает поведение программы непредсказуемым
- Слишком широкий блок
try— чем меньше кода вtry, тем точнее понятно, где именно возникает ошибка - Использование исключений для управления потоком вместо условий
if/else— исключения должны обрабатывать исключительные, а не штатные ситуации - Потеря трейсбека при перехвате — при повторном возбуждении исключения используйте
raiseбез аргументов, а неraise errorзаново
Частозадаваемые вопросы
Чем отличается except Exception от голого except?
except Exception перехватывает все «обычные» исключения, унаследованные от класса Exception, но не трогает BaseException-наследников вроде KeyboardInterrupt, SystemExit и GeneratorExit. Голый except перехватывает буквально всё, включая системные сигналы — это почти всегда нежелательно.
Можно ли использовать try/except внутри цикла? Да, и это распространённый паттерн. Например, при обработке списка данных можно перехватывать ошибки на каждой итерации, продолжая цикл вместо его прерывания:
results = []
for item in raw_data:
try:
results.append(int(item)) # Пробуем преобразовать каждый элемент
except ValueError:
results.append(None) # При ошибке ставим None и продолжаем
Как повторно выбросить исключение после его обработки?
Используйте raise без аргументов внутри блока except — это пробросит оригинальное исключение с сохранением трейсбека:
try:
risky_operation()
except ValueError as error:
logging.error(f"Поймали ValueError: {error}")
raise # Пробрасываем исключение дальше
Что такое цепочка исключений?
Python позволяет связывать исключения через raise NewException(...) from original_error. Это удобно при создании собственных исключений — сохраняется контекст исходной ошибки.
Когда использовать finally?
Блок finally нужен для кода, который должен выполниться в любом случае — освобождение ресурсов, закрытие соединений, запись в лог. Хотя менеджеры контекста (with) обычно решают эту задачу элегантнее.
Заключение
Механизм try/except — один из фундаментальных инструментов написания надёжного Python-кода. Ключевые принципы: всегда указывайте конкретные типы исключений, используйте as для получения деталей ошибки, не «проглатывайте» исключения молча, а для обязательного кода завершения применяйте finally.
Для закрепления навыков обработки исключений и других основ Python рекомендуем курс Основы Python. В первых 3 модулях курса доступно бесплатное содержание, что позволяет познакомиться с материалом, попрактиковаться на реальных задачах и понять структуру курса до покупки полного доступа.
Постройте личный план изучения Python до уровня Middle — бесплатно!
Python — часть карты развития Backend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Python
Лучшие курсы по теме

Основы Python
Антон Ларичев
Nest.js с нуля
Антон Ларичев