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

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

Почему именно так — как работает __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__. Пример:

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

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