1827 Stimmen

Der richtige Weg, um benutzerdefinierte Ausnahmen in modernen Python deklarieren?

Was ist der richtige Weg, um benutzerdefinierte Ausnahmeklassen in modernem Python zu deklarieren? Mein primäres Ziel ist es, zu folgen, was auch immer Standard andere Ausnahmeklassen haben, so dass (zum Beispiel) jede zusätzliche Zeichenfolge, die ich in der Ausnahme enthalten ist, von was auch immer Werkzeug die Ausnahme gefangen gedruckt.

Unter "modernem Python" verstehe ich etwas, das in Python 2.5 läuft, aber für Python 2.6 und Python 3.* "korrekt" ist. Und mit "benutzerdefiniert" meine ich eine Exception Objekt, das zusätzliche Daten über die Ursache des Fehlers enthalten kann: eine Zeichenkette, vielleicht auch ein anderes beliebiges Objekt, das für die Ausnahme relevant ist.

Ich wurde durch die folgende Verwerfungswarnung in Python 2.6.2 gestolpert:

>>> class MyError(Exception):
...     def __init__(self, message):
...         self.message = message
... 
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

Es scheint verrückt, dass BaseException hat eine besondere Bedeutung für Attribute mit dem Namen message . Ich entnehme PEP-352 dieses Attribut hatte in 2.5 eine besondere Bedeutung, die jetzt abgeschafft werden soll, also ist dieser Name (und nur dieser) jetzt wohl verboten? Pfui.

Ich bin mir auch unscharf bewusst, dass Exception hat einen magischen Parameter args aber ich habe nie gewusst, wie man es benutzt. Ich bin mir auch nicht sicher, ob es der richtige Weg ist, die Dinge in Zukunft zu tun; viele der Diskussionen, die ich online gefunden habe, deuten darauf hin, dass sie versuchen, args in Python 3 abzuschaffen.

Update: zwei Antworten haben vorgeschlagen, die __init__ y __str__ / __unicode__ / __repr__ . Das scheint eine Menge Tipparbeit zu sein, ist das notwendig?

62voto

mykhal Punkte 18078

Sehen, wie Ausnahmen standardmäßig funktionieren, wenn man gegen mehr Attribute verwendet werden (Rückverfolgung entfällt):

>>> raise Exception('bad thing happened')
Exception: bad thing happened

>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')

Sie sollten also vielleicht eine Art von " Ausnahmeschablone ", das selbst als Ausnahme funktioniert, auf kompatible Weise:

>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened

>>> raise nastyerr()
NastyError: bad thing happened

>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')

dies kann mit dieser Unterklasse leicht erreicht werden

class ExceptionTemplate(Exception):
    def __call__(self, *args):
        return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass

und wenn Sie diese standardmäßige tupelartige Darstellung nicht mögen, fügen Sie einfach __str__ Methode zum ExceptionTemplate Klasse, wie:

    # ...
    def __str__(self):
        return ': '.join(self.args)

und Sie haben

>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken

19voto

M. Utku ALTINKAYA Punkte 2216

Sie sollten Folgendes überschreiben __repr__ o __unicode__ Methoden anstelle von message verwenden, werden die Argumente, die Sie bei der Erstellung der Ausnahme angeben, in der args Attribut des Ausnahmeobjekts.

13voto

Yaroslav Nikitenko Punkte 1543

Siehe einen sehr guten Artikel " Der endgültige Leitfaden für Python-Ausnahmen ". Die Grundprinzipien sind:

  • Immer von (mindestens) Exception erben.
  • Immer anrufen BaseException.__init__ mit nur einem Argument.
  • Wenn Sie eine Bibliothek erstellen, definieren Sie eine Basisklasse, die von Exception erbt.
  • Geben Sie Einzelheiten über den Fehler an.
  • Vererben Sie von eingebauten Ausnahmetypen, wenn dies sinnvoll ist.

Es gibt auch Informationen über das Organisieren (in Modulen) und das Abwickeln von Ausnahmen, ich empfehle, den Leitfaden zu lesen.

10voto

Lennart Regebro Punkte 157632

Nein, "message" ist nicht verboten. Es ist nur veraltet. Ihre Anwendung wird auch mit message funktionieren. Aber Sie können natürlich den Verwerfungsfehler loswerden wollen.

Wenn Sie benutzerdefinierte Exception-Klassen für Ihre Anwendung erstellen, sind viele von ihnen nicht nur Unterklassen von Exception, sondern von anderen, wie ValueError oder ähnlich. Dann müssen Sie sich an deren Verwendung von Variablen anpassen.

Und wenn Sie viele Ausnahmen in Ihrer Anwendung haben, ist es in der Regel eine gute Idee, eine gemeinsame benutzerdefinierte Basisklasse für alle zu haben, so dass die Benutzer Ihrer Module Folgendes tun können

try:
    ...
except NelsonsExceptions:
    ...

Und in diesem Fall können Sie __init__ y __str__ benötigt, so dass Sie es nicht für jede Ausnahme wiederholen müssen. Aber es genügt, wenn Sie die Variable message mit einem anderen Namen als message aufrufen.

In jedem Fall benötigen Sie nur __init__ o __str__ wenn Sie etwas anderes tun, als Exception selbst tut. Und wegen der Veralterung braucht man dann beides, oder man bekommt einen Fehler. Das ist nicht sehr viel zusätzlicher Code, den man pro Klasse braucht.

6voto

SeekNDstroy Punkte 162

Ich hatte Probleme mit den oben genannten Methoden, ab Python 3.9.5. Allerdings fand ich, dass dies für mich funktioniert:

class MyException(Exception):
    """Port Exception"""

Und dann könnte es in einem Code wie diesem verwendet werden:

try:
    raise MyException('Message')

except MyException as err:
    print (err)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X