"Правильный способ объявить пользовательские исключения в современном Python?"
Это нормально, если только ваше исключение не является типом более конкретного исключения:
class MyException(Exception):
pass
Или лучше (может быть идеально), вместо того, чтобы pass
дать строку документации:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Подклассы Исключение Подклассы
Из документов
Exception
Все встроенные, не выходящие из системы исключения являются производными от этого класса. Все определяемые пользователем исключения также должны быть производными от этого класса.
Это означает, что если ваше исключение является типом более конкретного исключения, создайте подкласс этого исключения вместо универсального Exception
(и в результате вы все равно получите его, Exception
как рекомендуют документы). Кроме того, вы можете по крайней мере предоставить строку документации (и не быть вынужденным использовать pass
ключевое слово):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Установите атрибуты, которые вы создаете сами по себе __init__
. Старайтесь не передавать дикт в качестве позиционного аргумента, будущие пользователи вашего кода будут вам благодарны. Если вы используете устаревший атрибут сообщения, назначение его самостоятельно позволит избежать DeprecationWarning
:
class MyAppValueError(ValueError):
'''Raise when a specific subset of values in context of app is wrong'''
def __init__(self, message, foo, *args):
self.message = message # without this you may get DeprecationWarning
# Special attribute you desire with your Error,
# perhaps the value that caused the error?:
self.foo = foo
# allow users initialize misc. arguments as any other builtin Error
super(MyAppValueError, self).__init__(message, foo, *args)
Там действительно нет необходимости писать свой __str__
или __repr__
. Встроенные очень хороши, и ваше совместное наследование гарантирует, что вы используете его.
Критика топ-ответа
Может быть, я пропустил вопрос, но почему бы и нет
class MyException(Exception):
pass
Опять же, проблема с вышеприведенным заключается в том, что для того, чтобы поймать его, вам нужно будет либо указать его конкретно (импортировать, если он создан в другом месте), либо перехватить Exception, (но вы, вероятно, не готовы обрабатывать все типы исключений, и вы должны ловить только исключения, которые вы готовы обработать). Критика аналогична приведенной ниже, но, кроме того, это не способ инициализации через super
, и вы получите, DeprecationWarning
если получите доступ к атрибуту сообщения:
Изменить: чтобы переопределить что-то (или передать дополнительные аргументы), сделайте это:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super(ValidationError, self).__init__(message)
# Now for your custom code...
self.errors = errors
Таким образом, вы можете передать сообщение об ошибке второму параметру и перейти к нему позже с помощью e.errors
Это также требует, чтобы было передано ровно два аргумента (кроме self
.) Не больше, не меньше. Это интересное ограничение, которое будущие пользователи могут не оценить.
Быть прямым - нарушает подставляемость Лискова .
Я продемонстрирую обе ошибки:
>>> ValidationError('foo', 'bar', 'baz').message
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)
>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'
По сравнению с:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'