Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

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:


Inhaltsverzeichnis

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

  1. raise (ohne Argumente) wird verwendet, um die aktive Ausnahme in einer except-Suite erneut auszulösen.
  2. raise EXCEPTION wird verwendet, um eine neue Ausnahme auszulösen. Diese Form hat zwei Untervarianten: EXCEPTION kann eine Ausnahmeklasse oder eine Instanz einer Ausnahmeklasse sein; gültige Ausnahmeklassen sind BaseException und ihre Unterklassen (PEP 352). Wenn EXCEPTION eine 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

  1. Null- und Ein-Ausdruck-raise-Anweisungen bleiben unverändert.
  2. Zwei-Ausdruck-raise-Anweisungen werden umgewandelt von
    raise E, V
    

    zu

    raise E(V)
    

    Zwei-Ausdruck-throw()-Aufrufe werden umgewandelt von

    generator.throw(E, V)
    

    zu

    generator.throw(E(V))
    

    Siehe Punkt #5 für einen Vorbehalt zu dieser Transformation.

  3. Drei-Ausdruck-raise-Anweisungen werden umgewandelt von
    raise E, V, T
    

    zu

    e = E(V)
    e.__traceback__ = T
    raise e
    

    Drei-Ausdruck-throw()-Aufrufe werden umgewandelt von

    generator.throw(E, V, T)
    

    zu

    e = E(V)
    e.__traceback__ = T
    generator.throw(e)
    

    Siehe Punkt #5 für einen Vorbehalt zu dieser Transformation.

  4. Zwei- und drei-Ausdruck-raise-Anweisungen, bei denen E ein Tupelliteral ist, können mit dem raise-Fixer von 2to3 automatisch konvertiert werden. raise-Anweisungen, bei denen E ein Nicht-Literal-Tupel ist, z. B. das Ergebnis eines Funktionsaufrufs, müssen manuell konvertiert werden.
  5. Zwei- und drei-Ausdruck-raise-Anweisungen, bei denen E eine Ausnahmeklasse und V eine Ausnahmeinstanz ist, erfordern besondere Aufmerksamkeit. Diese Fälle lassen sich in zwei Lager aufteilen
    1. raise E, V als Langfassung der Null-Argument-raise-Anweisung. Als Beispiel, unter der Annahme, dass F eine Unterklasse von E ist
      try:
          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)
      
    2. raise E, V als Mittel zum „Casting“ einer Ausnahme in eine andere Klasse. Ein Beispiel aus distutils.compiler.unixcompiler
      try:
          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


Quelle: https://github.com/python/peps/blob/main/peps/pep-3109.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT