PEP 3109 – Exceptions in Python 3000 auslösen
- Autor:
- Collin Winter <collinwinter at google.com>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 19-Jan-2006
- Python-Version:
- 3.0
- Post-History:
Zusammenfassung
Dieses PEP führt Änderungen an Pythons Mechanismen zum Auslösen von Ausnahmen ein, die darauf abzielen, sowohl die Zeilenrauschen als auch die Größe der Sprache zu reduzieren.
Begründung
Eines der Leitmaximen von Python ist „Es sollte einen – und vorzugsweise nur einen – offensichtlichen Weg geben, dies zu tun“. Die raise-Anweisung von Python 2.x verstößt gegen dieses Prinzip und erlaubt mehrere Möglichkeiten, denselben Gedanken auszudrücken. Zum Beispiel sind diese Anweisungen äquivalent
raise E, V
raise E(V)
Es gibt eine dritte Form der raise-Anweisung, die es erlaubt, beliebige Tracebacks an eine Ausnahme anzuhängen [1]
raise E, V, T
wobei T ein Traceback ist. Wie in PEP 344 angegeben, werden Ausnahmeobjekte in Python 3.x ein __traceback__-Attribut besitzen, was diese Übersetzung der Drei-Ausdruck-raise-Anweisung zulässt
raise E, V, T
wird übersetzt zu
e = E(V)
e.__traceback__ = T
raise e
Mit diesen Übersetzungen können wir die raise-Anweisung von vier auf zwei Formen reduzieren
raise(ohne Argumente) wird verwendet, um die aktive Ausnahme in einerexcept-Suite erneut auszulösen.raise EXCEPTIONwird verwendet, um eine neue Ausnahme auszulösen. Diese Form hat zwei Untervarianten:EXCEPTIONkann eine Ausnahmeklasse oder eine Instanz einer Ausnahmeklasse sein; gültige Ausnahmeklassen sind BaseException und ihre Unterklassen (PEP 352). WennEXCEPTIONeine Unterklasse ist, wird sie ohne Argumente aufgerufen, um eine Ausnahmeinstanz zu erhalten.Alles andere auszulösen ist ein Fehler.
Es gibt einen weiteren, greifbareren Vorteil dieser Konsolidierung, wie A.M. Kuchling bemerkt hat [2].
PEP 8 doesn't express any preference between the
two forms of raise statements:
raise ValueError, 'blah'
raise ValueError("blah")
I like the second form better, because if the exception arguments
are long or include string formatting, you don't need to use line
continuation characters because of the containing parens.
Der BDFL hat zugestimmt [3] und die Konsolidierung der verschiedenen raise-Formen unterstützt.
Grammatikänderungen
In Python 3 wird sich die Grammatik für raise-Anweisungen von [1] ändern
raise_stmt: 'raise' [test [',' test [',' test]]]
zu
raise_stmt: 'raise' [test]
Änderungen an eingebauten Typen
Aufgrund seiner Beziehung zum Auslösen von Ausnahmen wird sich die Signatur der throw()-Methode für Generatorobjekte ändern, wobei die optionalen zweiten und dritten Parameter entfallen. Die Signatur ändert sich somit (PEP 342) von
generator.throw(E, [V, [T]])
zu
generator.throw(EXCEPTION)
wobei EXCEPTION entweder eine Unterklasse von BaseException oder eine Instanz einer Unterklasse von BaseException ist.
Semantische Änderungen
In Python 2 ist die folgende raise-Anweisung legal
raise ((E1, (E2, E3)), E4), V
Der Interpreter nimmt das erste Element des Tupels rekursiv als Ausnahmetyp, wodurch das obige vollständig äquivalent wird zu
raise E1, V
Ab Python 3.0 wird die Unterstützung für das Auslösen von Tupeln auf diese Weise eingestellt. Diese Änderung wird raise-Anweisungen mit der throw()-Methode für Generatorobjekte in Einklang bringen, die dies bereits verbietet.
Kompatibilitätsprobleme
Alle zwei- und drei-Ausdruck-raise-Anweisungen sowie alle zwei- und drei-Ausdruck-throw()-Aufrufe für Generatoren erfordern eine Änderung. Glücklicherweise ist die Übersetzung von Python 2.x zu Python 3.x in diesem Fall einfach und kann mechanisch vom 2to3-Dienstprogramm von Guido van Rossum [4] mithilfe der raise- und throw-Fixer ([5], [6]) behandelt werden.
Die folgenden Übersetzungen werden durchgeführt
- Null- und Ein-Ausdruck-
raise-Anweisungen bleiben unverändert. - Zwei-Ausdruck-
raise-Anweisungen werden umgewandelt vonraise E, V
zu
raise E(V)
Zwei-Ausdruck-
throw()-Aufrufe werden umgewandelt vongenerator.throw(E, V)
zu
generator.throw(E(V))
Siehe Punkt #5 für einen Vorbehalt zu dieser Transformation.
- Drei-Ausdruck-
raise-Anweisungen werden umgewandelt vonraise E, V, T
zu
e = E(V) e.__traceback__ = T raise e
Drei-Ausdruck-
throw()-Aufrufe werden umgewandelt vongenerator.throw(E, V, T)
zu
e = E(V) e.__traceback__ = T generator.throw(e)
Siehe Punkt #5 für einen Vorbehalt zu dieser Transformation.
- Zwei- und drei-Ausdruck-
raise-Anweisungen, bei denenEein Tupelliteral ist, können mit demraise-Fixer von2to3automatisch konvertiert werden.raise-Anweisungen, bei denenEein Nicht-Literal-Tupel ist, z. B. das Ergebnis eines Funktionsaufrufs, müssen manuell konvertiert werden. - Zwei- und drei-Ausdruck-
raise-Anweisungen, bei denenEeine Ausnahmeklasse undVeine Ausnahmeinstanz ist, erfordern besondere Aufmerksamkeit. Diese Fälle lassen sich in zwei Lager aufteilenraise E, Vals Langfassung der Null-Argument-raise-Anweisung. Als Beispiel, unter der Annahme, dass F eine Unterklasse von E isttry: something() except F as V: raise F(V) except E as V: handle(V)
Dies wäre besser ausgedrückt als
try: something() except F: raise except E as V: handle(V)
raise E, Vals Mittel zum „Casting“ einer Ausnahme in eine andere Klasse. Ein Beispiel aus distutils.compiler.unixcompilertry: self.spawn(pp_args) except DistutilsExecError as msg: raise CompileError(msg)
Dies wäre besser ausgedrückt als
try: self.spawn(pp_args) except DistutilsExecError as msg: raise CompileError from msg
Verwendung der
raise ... from ...-Syntax, eingeführt in PEP 344.
Implementierung
Dieses PEP wurde in Revision 57783 implementiert [7].
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-3109.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT