Почему при raise MyError получается TypeError

Почему при raise MyError получается TypeError

@python_quiz

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

Коротко: в приведённом коде попытка поднять класс исключения без создания его экземпляра приводит к ошибке при инстанцировании — и в итоге в блоке except попадает TypeError.

Исходный код

python

Что здесь происходит — пошагово

  1. Определён класс MyError, унаследованный от Exception. Его __init__ требует один аргумент — msg.
  2. В блоке try выполняется raise MyError. Это не raise MyError() и не raise MyError('...'), а ссылка на сам класс.
  3. Когда вы делаете raise <класс>, интерпретатор пытается создать экземпляр этого класса, вызвав конструктор без аргументов.
  4. Поскольку MyError.__init__ требует обязательный параметр msg, попытка инстанцировать класс без аргумента вызывает TypeError (недостаточно аргументов для __init__).
  5. Этот TypeError перехватывается except Exception as e, и затем печатается имя класса исключения — "TypeError".

Если запустить пример, в выводе будет:

text

Варианты, которые могли бы случиться (и почему они не происходят)

  • "Исключение MyError": это могло быть, если бы класс имел конструктор с подписью, позволяющей вызов без аргументов (например, __init__(self, msg=None)) или если бы вы поднимали уже созданный экземпляр.
  • "Экземпляр MyError": это произошло бы, если бы вы явно подняли экземпляр, например raise MyError('something'). Тогда except поймает экземпляр MyError и тип напечатает "MyError".
  • "Ничего не будет поймано": неверно, потому что при инстанцировании класса действительно возникает TypeError, а он наследуется от Exception — следовательно, будет пойман.

Демонстрация других вариантов

1) Поднять экземпляр явно:

python

Вывод:

text

2) Сделать msg опциональным, тогда raise MyError сработает:

python

Вывод:

text

Практические рекомендации

  • Обычно лучше делать аргументы __init__ у исключений опциональными (msg=None) или наследовать стандартные Exception, позволяя передавать строку в базовый класс: super().__init__(msg). Так исключение можно безопасно как поднимать классом, так и экземпляром.
  • Предпочтительнее явно поднимать экземпляр (raise MyError("desc")) — это явнее и предсказуемее.
  • Помните: raise <класс> приводит к автоматическому вызову конструктора без аргументов; если конструктор требует аргументы, это приведёт к TypeError во время raise.

Итог

В исходном коде raise MyError приводит к попытке создать экземпляр без аргумента, это вызывает TypeError при вызове __init__, и именно этот TypeError перехватывается и печатается.

Report Page