"Was ist der richtige Weg, um benutzerdefinierte Ausnahmen in modernem Python zu deklarieren?"
Dies ist in Ordnung, es sei denn, Ihre Ausnahme ist wirklich ein Typ einer spezifischeren Ausnahme:
class MyException(Exception):
pass
Oder besser (vielleicht perfekt), anstelle von pass
einen Docstring geben:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Unterklassenbildung von Ausnahme-Unterklassen
Von der docs
Exception
Alle eingebauten, nicht systembedingten Ausnahmen sind von dieser Klasse abgeleitet. Alle benutzerdefinierten Ausnahmen sollten ebenfalls von dieser Klasse abgeleitet werden. Klasse abgeleitet werden.
Das bedeutet, dass wenn Ihre Ausnahme ein Typ einer spezifischeren Ausnahme ist, untergliedern Sie diese Ausnahme anstelle der generischen Exception
(und das Ergebnis wird sein, dass Sie immer noch von Exception
wie in der Dokumentation empfohlen). Außerdem können Sie zumindest einen Docstring angeben (und sind nicht gezwungen, die pass
Schlüsselwort):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Setzen Sie Attribute, die Sie selbst mit einer benutzerdefinierten __init__
. Vermeiden Sie die Übergabe eines dict als Positionsargument, zukünftige Benutzer Ihres Codes werden es Ihnen danken. Wenn Sie das veraltete message-Attribut verwenden, vermeiden Sie durch die eigene Zuweisung ein 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)
Es ist wirklich nicht nötig, einen eigenen Text zu schreiben. __str__
o __repr__
. Die eingebauten sind sehr schön, und Ihre genossenschaftliches Erbe sorgt dafür, dass Sie sie nutzen.
Kritik an der besten Antwort
Vielleicht habe ich die Frage nicht verstanden, aber warum nicht?
class MyException(Exception):
pass
Auch hier besteht das Problem darin, dass Sie sie entweder speziell benennen müssen (indem Sie sie importieren, wenn sie an anderer Stelle erstellt wurde) oder eine Ausnahme abfangen müssen (aber Sie sind wahrscheinlich nicht darauf vorbereitet, alle Arten von Ausnahmen zu behandeln, und Sie sollten nur Ausnahmen abfangen, auf deren Behandlung Sie vorbereitet sind). Ähnliche Kritik wie unten, aber zusätzlich ist das nicht die Art und Weise der Initialisierung über super
und Sie erhalten eine DeprecationWarning
wenn Sie auf das Nachrichtenattribut zugreifen:
Bearbeiten: um etwas zu überschreiben (oder zusätzliche Args zu übergeben), tun Sie dies:
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
Auf diese Weise könnten Sie dict von Fehlermeldungen an den zweiten Parameter übergeben, und später mit e.errors darauf zugreifen
Außerdem müssen genau zwei Argumente übergeben werden (abgesehen von der self
.) Nicht mehr und nicht weniger. Das ist eine interessante Einschränkung, die künftige Nutzer vielleicht nicht zu schätzen wissen.
Um es direkt zu sagen: Es verstößt gegen Liskov-Substituierbarkeit .
Ich werde beide Fehler demonstrieren:
>>> 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'
Verglichen mit:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'