Как работает `raise ... from None` и атрибут `__cause__` в Python

Как работает `raise ... from None` и атрибут `__cause__` в Python

@python_quiz

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

Коротко: приведённый код поднимает пользовательское исключение и явно сбрасывает связь с предыдущим исключением. В результате атрибут __cause__ будет равен None, а сам выброшенный тип — тот, что мы подняли (здесь ConfigError).

Условие (код для анализа)

python

Что выведет код

Этот код напечатает:

Пояснение: мы поднимаем ConfigError и явно указываем from None, поэтому у объекта исключения __cause__ будет значение None.

Почему так — разбор механики исключений

В Python есть два связанных понятия, относящихся к "цепочке" исключений:

  • __context__ — хранит предыдущее исключение, которое произошло автоматически (например, если во время обработки исключения возникло новое).
  • __cause__ — хранит явную причину, указанную через raise NewError from original_error.
  • __suppress_context__ — булево значение, которое становится True, когда используется from None, что подавляет автоматическое отображение __context__.

Когда пишут raise NewError from None, это означает:

  • Явная причина (__cause__) устанавливается в None.
  • Подавляется автоматическое отображение контекста (__suppress_context__ = True).
  • В итоге в трассировке и у атрибутов связи нет «предыдущего» исключения.

В нашем примере никакого предыдущего исключения и не было, но from None всё равно явно задаёт отсутствие причины.

Разбор предложенных вариантов (логические выводы)

  • "ConfigError -> FileNotFoundError('config.yml')" — неверно: для такого вывода нужно было бы, чтобы __cause__ ссылалось на объект FileNotFoundError, чего в коде нет.
  • "ConfigError -> None" — соответствует реальному выводу: тип исключения ConfigError, а __cause__ равен None.
  • "FileNotFoundError -> None" — неверно: сам выброшенный тип — ConfigError, а не FileNotFoundError.
  • "ConfigError -> FileNotFoundError без текста" — неверно: здесь __cause__ не содержит FileNotFoundError вообще.

Дополнительные примеры для наглядности

1) Пример явной цепочки (без None):

python

Ожидаемый вывод:

2) Пример с from None подавляющим контекст:

python

Ожидаемый вывод:

Обратите внимание: __context__ может всё ещё хранить предыдущее исключение, но __cause__ явно равен None и __suppress_context__ препятствует печати контекста в трассировке.

Вывод

Использование raise ... from None явно сбрасывает связь причин исключений — __cause__ становится None, и автоматическое отображение контекста подавляется. В демонстрируемом коде это приводит к выводу: "ConfigError -> None".

Report Page