«Правильный способ объявления пользовательских исключений в современном 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'