Исключения в Python: как работает __cause__ при raise ... from

Исключения в Python: как работает __cause__ при raise ... from

@python_quiz

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

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

Исходный код

python

Пошаговый разбор

  1. Объявляется собственный класс исключения ParseError, унаследованный от Exception.
  2. В блоке try создаётся исключение ValueError("x") и сохраняется в переменную v.
  3. Затем выполняется raise ParseError("bad int") from v. Это:

- создаёт новое исключение ParseError("bad int"),
- связывает его с v (источником) через атрибут __cause__.

  1. Пойманное ParseError попадает в except ParseError as e, и мы обращаемся к e.__cause__.
  2. 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__, и его имя выводится на экран.

Report Page