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

Пошаговый разбор
- Объявляется собственный класс исключения
ParseError, унаследованный отException. - В блоке
tryсоздаётся исключениеValueError("x")и сохраняется в переменнуюv. - Затем выполняется
raise ParseError("bad int") from v. Это:
- создаёт новое исключение ParseError("bad int"),
- связывает его с v (источником) через атрибут __cause__.
- Пойманное
ParseErrorпопадает вexcept ParseError as e, и мы обращаемся кe.__cause__. type(e.__cause__).__name__берёт имя класса объекта-источника исключения — в данном случае этоValueError.
Что такое __cause__ и чем он отличается от __context__
__cause__— устанавливается явно черезraise NewException from original_exception.__context__— хранит предыдущее исключение автоматически, если новое исключение поднято в обработчике исключения и не используетсяfrom.- Если используется
from None, то связь через__cause__подавляется (в таком случае__cause__будетNone, но__context__может всё равно указывать на предыдущую ошибку).
Демонстрация результата
Запустив приведённый код, на вывод попадёт текст:

Почему именно так: e.__cause__ — это объект ValueError("x"), а type(...).__name__ возвращает строковое имя класса — ValueError.
Анализ вариантов (коротко)
ParseError— это класс нового исключения, но он не является причиной (__cause__).- Exception — общее базовое исключение; не соответствует конкретному объекту в
__cause__. ValueError— соответствует объекту, переданному вfrom, поэтому имя класса будет именноValueError.- None — означало бы отсутствие причины; в данном примере причина задана явно, соответственно
__cause__неNone.
Вывод
Использование raise ... from позволяет явно связать одно исключение с другим. Это удобно для сохранения контекста ошибки при переводе низкоуровневых исключений в более высокоуровневые, не теряя исходной информации. В коде выше именно исходное исключение ValueError хранится в e.__cause__, и его имя выводится на экран.