Как работают вложенные исключения в Python?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Вложенные исключения, также известные как связанность исключений or exception chaining, позволяют сохранять информацию о предыдущем исключении при возникновении нового. Это полезно для отладки и понимания причин ошибки.
В Python 3 по умолчанию при возникновении нового исключения внутри блока except или finally, исходное исключение автоматически связывается с новым.
Эта связь хранится в атрибуте __cause__ нового исключения.
Явное связывание может быть выполнено с помощью ключевого слова raise from.
# Пример автоматического связывания
def divide(a, b):
try:
return a / b
except TypeError:
# Во время обработки TypeError может возникнуть другое исключение
# Original exception (TypeError) будет связано с новым
raise ValueError("Неправильный тип операндов")
try:
divide("a", 0)
except ValueError as e:
# e.__cause здесь будет содержать TypeError
print(f"Произошла ошибка: {e}")
if e.__cause__:
print(f"Вызвано из: {e.__cause__}")
print("-" * 20)
# Пример явного связывания с raise from
class CustomError(Exception):
pass
def tricky_function():
try:
# Попытка деления на ноль, вызывает ZeroDivisionError
result = 1 / 0
except ZeroDivisionError as original_exc:
# Создаем новое исключение и связываем его с оригинальным
raise CustomError("Ошибка при вычислении") from original_exc
try:
tricky_function()
except CustomError as e:
# e.__cause__ здесь будет содержать ZeroDivisionError
print(f"Произошла ошибка: {e}")
if e.__cause__:
print(f"Вызвано из: {e.__cause__}")
print("-" * 20)
# Подавление связывания с raise ... from None
try:
try:
# Исходное исключение
raise ValueError("Исходная ошибка")
except ValueError:
# Во время обработки ValueError возникает другое исключение,
# но связывание подавляется
raise TypeError("Новая ошибка") from None
except TypeError as e:
# e.__cause__ здесь будет None
print(f"Произошла ошибка: {e}")
if e.__cause__ is None:
print("Причина не указана.")
Ключевое слово raise без аргументов повторно возбуждает последнее исключение.
# Пример повторного возбуждения исключения
def process_data(data):
try:
# Предположим, здесь что-то может пойти не так
if not data:
raise ValueError("Данные отсутствуют")
print("Данные обработаны")
except ValueError:
print("Перехватили ValueError")
# Повторно возбуждаем то же исключение
raise
try:
process_data("")
except ValueError as e:
print(f"Перехватили повторно возбужденное исключение: {e}")
Вложенные исключения улучшают читаемость трассировок ошибок и помогают быстрее локализовать первопричину проблемы.