raise ... from и атрибут __cause__ в Python
@python_quizРазберем этот квиз
Небольшой фрагмент кода показывает важную деталь обработки исключений в Python — как явно связать одно исключение с другим с помощью raise ... from. Давайте разберём код, увидим результат и объясним варианты.
Код из квиза

Этот код печатает имя класса того исключения, которое было указано после from.
Что делает raise ... from?
- Оператор
raise NewExc from OldExcявно устанавливает связь между новым исключением (NewExc) и исходным (OldExc). - При этом исходное исключение сохраняется в атрибуте
__cause__нового исключения. - Если исключение было сгенерировано автоматически в процессе обработки другого исключения (без
from), то исходный объект попадает в__context__, а__cause__остаётсяNone, если не использованfrom.
Демонстрация результата
Запустим код — он выведет имя класса исключения, записанного в __cause__:

Вывод:

Анализ вариантов ответов
Допустим, в вариантах были: RuntimeError, ValueError, TypeError, None. Разберём их логически.
RuntimeError
Это исключение, которое мы подняли в блоке try. Но __cause__ — это не само текущее исключение, а связанное исходное. Поэтому RuntimeError в __cause__ не окажется.
ValueError
Именно это исключение было передано после from, и оно помещается в __cause__ нового исключения. В результате type(e.__cause__).__name__ вернёт ValueError.
TypeError
Никакой TypeError здесь не создаётся и не связывается с RuntimeError, поэтому этот вариант неверен.
- None
