Поведение __cause__ и __context__ в исключениях Python
@python_quizРазберем этот квиз
Коротко: код вручную связывает два атрибута исключения с одним объектом-исключением. В результате выводит имя типа исходного исключения и True для проверки идентичности ссылки.
Условие (код)

Пошаговый разбор
- Создаем класс
DataError, наследник Exception. - Создаем объект e типа
ValueErrorс сообщением 'raw'. - Создаем объект d типа
DataErrorс сообщением 'wrapped'. - Явно присваиваем d.
__cause__ = eи d.__context__ = e— оба атрибута теперь ссылаются на один и тот же объект e. - В выражении print берём type(d.
__cause__).__name__— это имя класса объекта, на который ссылается__cause__(то есть "ValueError"). - Сравниваем d.
__cause__is d.__context__— это проверка по идентичности объектов; так как обе ссылки указывают на один объект e, результат будет True.
Итоговый вывод программы:

Демонстрация (запустите в Python)

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

Анализ вариантов ответов
- "Выведет:
ValueError-> True" — соответствует поведению кода: тип объекта, на который указывает__cause__, —ValueError, и обе переменные ссылаются на один объект, так что is вернёт True. - "Выведет:
ValueError-> False" — неверно, потому что здесь__cause__и__context__явно назначены на один и тот же объект. - "Выведет:
DataError-> False" — неверно: тип__cause__— неDataError, аValueError, и у нас не разные объекты. - "Будет поднято необработанное исключение" — неверно: в коде исключение не поднимается после создания; мы просто вручную присваиваем атрибуты — никаких необработанных исключений не возникает.
Небольшие замечания о __cause__ и __context__
- Атрибуты
__cause__и__context__— обычные ссылки на объекты исключений; их можно присваивать вручную (как в примере) или они могут устанавливаться интерпретатором при цепочке исключений. - Оператор "raise ... from ..." используется для явного задания причины — это влияет на отображение цепочки при печати трассировки, но в данном квизе мы работаем с явным присваиванием.
- Проверка is сравнивает идентичность объектов (т.е. указывает ли ссылка на тот же объект), а не только эквивалентность по значениям.
Вывод
Код печатает имя типа исходного исключения и True, потому что оба атрибута __cause__ и __context__ указывают на один и тот же объект ValueError. Это простой пример, который показывает разницу между типом исключения, ссылками на объекты и тем, как Python хранит информацию о цепочке исключений.