"Modo corretto per dichiarare eccezioni personalizzate nel moderno Python?"
Questo va bene, a meno che la tua eccezione non sia in realtà un tipo di eccezione più specifica:
class MyException(Exception):
pass
O meglio (forse perfetto), invece di pass
dare una dotstring:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Sottoclassi Sottoclassi di eccezione
Dai documenti
Exception
Tutte le eccezioni integrate, non esistenti nel sistema, derivano da questa classe. Anche tutte le eccezioni definite dall'utente devono essere derivate da questa classe.
Ciò significa che se la tua eccezione è un tipo di eccezione più specifica, esegui la sottoclasse di tale eccezione anziché quella generica Exception
(e il risultato sarà che continuerai a derivare Exception
come raccomandato dai documenti). Inoltre, puoi almeno fornire un docstring (e non essere obbligato a usare la pass
parola chiave):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Imposta gli attributi che ti crei con un'abitudine __init__
. Evita di passare un dict come argomento posizionale, i futuri utenti del tuo codice ti ringrazieranno. Se si utilizza l'attributo del messaggio obsoleto, assegnandolo da soli si eviterà 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)
Non c'è davvero bisogno di scrivere il tuo __str__
o __repr__
. Quelli incorporati sono molto belli e la tua eredità cooperativa ti assicura di usarlo.
Critica della risposta migliore
Forse ho perso la domanda, ma perché no:
class MyException(Exception):
pass
Ancora una volta, il problema con quanto sopra è che per prenderlo, dovresti nominarlo in modo specifico (importandolo se creato altrove) o catturare Eccezione (ma probabilmente non sei pronto a gestire tutti i tipi di Eccezioni, e dovresti rilevare solo le eccezioni che sei disposto a gestire). Critiche simili a quelle riportate di seguito, ma in più non è questo il modo di inizializzare tramite super
e otterrai un DeprecationWarning
accesso se accedi all'attributo message:
Modifica: per sovrascrivere qualcosa (o passare argomenti extra), procedere come segue:
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
In questo modo è possibile passare messaggi di errore al secondo parametro e accedervi successivamente con e.errors
Richiede inoltre di passare esattamente due argomenti (a parte il self
.) Niente di più, niente di meno. Questo è un vincolo interessante che i futuri utenti potrebbero non apprezzare.
Ad essere diretti - viola la sostituibilità di Liskov .
Dimostrerò entrambi gli errori:
>>> 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'
Rispetto a:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'