Назад к вопросам
Middle
74
questionbank

Как работают вложенные исключения в 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}")

Вложенные исключения улучшают читаемость трассировок ошибок и помогают быстрее локализовать первопричину проблемы.