"¿Forma correcta de declarar excepciones personalizadas en Python moderno?"
Esto está bien, a menos que su excepción sea realmente un tipo de excepción más específica:
class MyException(Exception):
pass
O mejor (tal vez perfecto), en lugar de pass
dar una cadena de documentación:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Subclases Excepción Subclases
De los documentos
Exception
Todas las excepciones integradas que no salen del sistema se derivan de esta clase. Todas las excepciones definidas por el usuario también deben derivarse de esta clase.
Eso significa que si su excepción es un tipo de excepción más específica, subclase esa excepción en lugar de la genérica Exception
(y el resultado será el que aún deriva Exception
como lo recomiendan los documentos). Además, al menos puede proporcionar una cadena de documentación (y no verse obligado a usar la pass
palabra clave):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Establezca atributos que cree usted mismo con una costumbre __init__
. Evite pasar un dict como argumento posicional, los futuros usuarios de su código se lo agradecerán. Si usa el atributo de mensaje en desuso, asignándolo usted mismo evitará un 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)
En realidad no hay necesidad de escribir su propio __str__
o __repr__
. Los incorporados son muy agradables y su herencia cooperativa asegura que lo use.
Crítica de la respuesta superior
Tal vez me perdí la pregunta, pero por qué no:
class MyException(Exception):
pass
Una vez más, el problema con lo anterior es que para atraparlo, tendrá que nombrarlo específicamente (importándolo si se creó en otro lugar) o atrapar Exception (pero probablemente no esté preparado para manejar todo tipo de Excepciones, y solo debe detectar las excepciones que está preparado para manejar). Crítica similar a la siguiente, pero además esa no es la forma de inicializar a través de super
, y obtendrá un DeprecationWarning
si accede al atributo de mensaje:
Editar: para anular algo (o pasar argumentos adicionales), haga esto:
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
De esa forma, puede pasar mensajes de error de error al segundo parámetro y acceder a él más tarde con e.errors
También requiere que se pasen exactamente dos argumentos (aparte del self
.) Ni más ni menos. Esa es una restricción interesante que los futuros usuarios pueden no apreciar.
Para ser directo, viola la sustituibilidad de Liskov .
Demostraré ambos errores:
>>> 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'
Comparado con:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'