Цепочки исключений в Python: __cause__ и raise ... from

Цепочки исключений в Python: __cause__ и raise ... from

@python_quiz

Разберем этот квиз

Коротко — в примере используется синтаксис raise ... from ..., который явно связывает новое исключение с исходным. Разберём код, увидим вывод и объясним, почему именно так.

Исходный код и вывод

Код из квиза:

python

При запуске этот фрагмент напечатает:

Почему именно так — как работает __cause__

  • Оператор raise NewException(...) from OriginalException(...) устанавливает атрибут __cause__ у вновь поднятого исключения.
  • В данном случае ConfigError — новое исключение, а FileNotFoundError — причина. Поэтому e.__cause__ у перехваченного ConfigError ссылается на объект FileNotFoundError.
  • Выражение type(e.__cause__).__name__ возвращает имя класса этой причины — FileNotFoundError.

Разбор вариантов (коротко)

  • ConfigError — это тип самого перехваченного исключения; но в коде берётся именно e.__cause__, а не e или type(e).
  • FileNotFoundError — тип причины, установленной через from, и именно его имя выводится.
  • Exception — базовый класс; причина является более специфичным подклассом Exception, поэтому имя конкретного класса — не Exception.
  • None — могло бы быть, если бы причина не была установлена (raise ... без from), тогда __cause__ равен None.

Что если убрать from — демонстрация

Если не использовать from, Python устанавливает другой атрибут: __context__. Пример:

python

Один из возможных выводов:

Объяснение:

  • __cause__ — None, потому что from не использовался.
  • __context__ содержит предыдущее (необработанное) исключение — FileNotFoundError.

Несколько полезных замечаний

  • raise ... from None очищает цепочку: устанавливает __cause__ в None и подавляет автоматическую печать контекста в трейсбэке.
  • __suppress_context__ — флаг, позволяющий управлять выводом контекста в трейсбэке.
  • Явное связывание через from полезно, когда вы хотите показать, что одно исключение является прямой причиной другого (более прозрачный трейсбэк).

Вывод

Использование raise New(...) from Old(...) связывает исключения так, что у нового исключения в __cause__ будет объект исходного. В примере это приводит к выводу имени класса причины — FileNotFoundError. Понимание разницы между __cause__ и __context__ помогает правильно оформлять и читать трейсбэки в сложных ситуациях.

Report Page