Python: пользовательское исключение, которое подтверждает правило
Документация на Python состояния:
Исключения обычно должны быть получены из класса Exception, прямо или косвенно.
слово 'typically'
оставляет меня в неоднозначном состоянии.
рассмотрим код:
class good(Exception): pass
class bad(object): pass
Heaven = good()
Hell = bad()
>>> raise Heaven
Traceback (most recent call last):
File "<pyshell#163>", line 1, in <module>
raise Heaven
good
>>> raise Hell
Traceback (most recent call last):
File "<pyshell#171>", line 1, in <module>
raise Hell
TypeError: exceptions must be classes or instances, not bad
поэтому, читая документы python, я должен заменить 'typically'
на ''
?
что если у меня есть иерархия классов, которая не имеет ничего общего с классом Exception, и я хочу "поднять" объекты, принадлежащие иерархии?
Я всегда могу вызвать исключение с аргументом:
raise Exception, Hell
Мне это кажется немного неудобным
Что такого особенного в классе Exception (EDIT: или BaseException), что могут быть подняты только члены его семейства?
Ответы
Ответ 1
", поэтому, читая документы python, должен ли я изменить" обычно "на"?"?
Нет.
Как правило, вы наследуете от Exception. Период. Это то, что он говорит.
Иногда вы можете наследовать от BaseException. Это то, что он не говорит. Вы можете расширить BaseExcetion, потому что хотите уничтожить обработчики except Exception
.
Что особенно важно...
Это подклассы BaseException
. Что еще нужно знать? Источник легко доступен. Вы можете прочитать исходный код для оператора raise
, чтобы увидеть, что именно он проверяет, прежде чем он вытащит TypeError
.
http://svn.python.org/view/python/trunk/Python/ceval.c?annotate=80817
Строки 3456 - 3563.
Однако все, что имеет значение с практической точки зрения, - это "подклассы BaseException
".
Ответ 2
Существуют и другие допустимые классы, которые вы можете наследовать, кроме Exception
, например BaseException
.
См. документацию для иерархии исключений.
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
etc..
В более старых версиях Python было возможно бросить вещи, кроме исключений. Например, в Python 2.5:
>>> raise "foo"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
foo
Но вы получите это предупреждение об отказе:
DeprecationWarning: raising a string exception is deprecated
В новых версиях это недопустимо. Все, что вы делаете, должно происходить из BaseException.
Ответ 3
"Обычно" используется, потому что существует несколько очень редких типов исключений, которые не хотят быть пойманы универсальным обработчиком Exception
. Если сомнение наследуется от Exception
, но есть исключения из этого правила.
Большинство исключений используются для указания какой-либо ошибки или исключительного условия, которое является результатом кода и данных. Эти исключения - все подклассы Exception
. Если вы хотите создать собственное исключение, оно, вероятно, попадет в эту категорию и поэтому также наследует Exception
. Если вам нужен общий обработчик исключений, например. чтобы регистрировать ошибки, тогда вполне разумно поймать Exception
и ожидать, что поймают любые ошибки таким образом.
Другие исключения, которые наследуются непосредственно из BaseException
, немного отличаются. SystemExit
возникает при вызове sys.exit()
(или вы можете поднять его напрямую). Если у вас есть код верхнего уровня, который регистрирует ошибки, вы, вероятно, не хотите, чтобы он обрабатывал SystemExit
таким же образом. Раньше вам приходилось включать отдельный обработчик для SystemExit
только для того, чтобы остановить общий обработчик Exception в этом случае.
KeyboardInterrupt
представляет собой непредвиденное условие, но оно вызвано внешним вводом от пользователя, чтобы оно могло происходить в любом месте вашего кода; это никоим образом не зависит от кода или данных. Это означает, что даже если вы хотите обработать его, вы, вероятно, захотите обработать его иначе, чем исключения, которые наследуются от Exception
.
Ответ 4
Вещи, полученные из различных классов ошибок/исключений, также могут быть подняты, но они обычно зарезервированы для других вещей.
Ответ 5
Иногда вам может понадобиться поднять то, что вы не считаете исключением (но правило). Для этих редких случаев можно с удовольствием относиться к raise
к чему-то другому, кроме исключений.
В рекурсивном вычислении, в котором в какой-то момент найдется ответ, поднятие его на ожидающий вверх зрелище может быть довольно аккуратным (вместо return
ing, что означает, что рекурсия должна ожидать этого, также передать его вверх и др.).
Но в наши дни только классы старого стиля (по соображениям совместимости) и вывод из BaseException могут быть подняты, потому что слишком много людей злоупотребляют такими вещами, как строки для исключений.