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

Python Enhancement Proposals

PEP 760 – Keine leeren Except-Klauseln mehr

Autor:
Pablo Galindo <pablogsal at python.org>, Brett Cannon <brett at python.org>
Status:
Zurückgezogen
Typ:
Standards Track
Erstellt:
02-Okt-2024
Python-Version:
3.14
Post-History:
09-Oct-2024

Inhaltsverzeichnis

Zusammenfassung

Dieses PEP schlägt vor, leere except:-Klauseln in der Python-Exception-Handling-Syntax zu verbieten. Derzeit erlaubt Python das Abfangen aller Ausnahmen mit einer leeren except:-Klausel, was zu einer zu breiten Ausnahmebehandlung führen und wichtige Fehler maskieren kann. Dieses PEP schlägt vor, explizite Ausnahmetypen in allen Except-Klauseln zu verlangen, um eine präzisere und gezieltere Fehlerbehandlung zu fördern.

Motivation

Die aktuelle Syntax erlaubt das Abfangen aller Ausnahmen mit einer leeren except:-Klausel

try:
    risky_operation()
except:
    handle_any_error()

Auch wenn diese Syntax für einen „Catch-All“-Handler praktisch sein kann, führt sie oft zu schlechten Programmierpraktiken

  1. Sie kann wichtige Fehler maskieren, die weitergegeben werden sollten.
  2. Sie erschwert das Debugging, indem sie unerwartete Ausnahmen abfängt und potenziell verbirgt.
  3. Sie widerspricht dem Python-Prinzip „Explizit vor implizit“.

Verschiedene Linter [1] [2] [3] und Styleguides (einschließlich PEP 8) [4] [5] [6] [7] raten von leeren except-Klauseln ab.

Durch die Anforderung expliziter Ausnahmetypen können wir eine durchdachtere und präzisere Fehlerbehandlung fördern

try:
    risky_operation()
except Exception as e:
    handle_expected_error(e)

Eine weitere Sichtweise auf dieses Problem ist, dass leere Except-Handler mehrdeutig sind, was die beabsichtigte Behandlung von terminierenden Ausnahmen betrifft, da die Absicht entweder gewesen sein könnte:

  • Nur nicht-terminierende Ausnahmen abfangen (except Exception:). Wenn dies die Absicht war, ist die Verwendung einer leeren except: ein offensichtlicher Fehler, da dies nicht ihre Bedeutung ist.
  • Alle Ausnahmen abfangen, einschließlich terminierender (except BaseException:). Die Verwendung von leerem except: ist hier zumindest korrekt, aber die Leser müssen prüfen, um sicher zu sein, dass es sich nicht um eine Instanz des ersten Falls handelt.

Da beide möglichen Absichten verfügbare, eindeutige Schreibweisen haben, ist die mehrdeutige Form überflüssig, und deshalb schlagen wir vor, sie zu verbieten.

Begründung

Die Entscheidung, leere Except-Klauseln zu verbieten, basiert auf den folgenden Überlegungen:

  1. Das Erfordernis spezifischer Ausnahmetypen macht die Absichten des Programmierers klar und regt zum Nachdenken über mögliche Ausnahmen an.
  2. Das Abfangen nur spezifischer Ausnahmen erleichtert die Identifizierung und Behebung unerwarteter Fehler.
  3. Das Verhindern einer zu breiten Ausnahmebehandlung reduziert das Risiko, kritische Fehler stillschweigend zu ignorieren.
  4. Viele Styleguides und Linter raten bereits von der Verwendung leerer Except-Klauseln ab.

Spezifikation

Die Syntax für die Except-Klausel wird geändert, um einen Ausnahmetyp zu erfordern. Die Grammatik wird aktualisiert, um die Möglichkeit zu entfernen, leere Ausdrücke in Except-Klauseln hinzuzufügen.

Diese Änderung verbietet die Syntax except:. Alle Except-Klauseln müssen mindestens einen Ausnahmetyp angeben

try:
    ...
except ValueError:
    ...
except (TypeError, RuntimeError):
    ...
except Exception:
    ...  # Still allowed, but catches all exceptions explicitly

Die Semantik der Ausnahmebehandlung bleibt unverändert, außer dass es nicht mehr möglich sein wird, alle Ausnahmen abzufangen, ohne explizit BaseException oder einen ähnlich breiten Ausnahmetyp anzugeben.

Abwärtskompatibilität

Diese Änderung ist nicht abwärtskompatibel. Vorhandener Code, der leere except:-Klauseln verwendet, muss angepasst werden. Um den Übergang zu erleichtern

  1. Eine Deprecation-Warnung wird für leere Except-Klauseln in Python 3.14 ausgegeben.
  2. Die Syntax wird in Python 3.17 vollständig verboten.
  3. Ein from __future__ import strict_excepts wird bereitgestellt, um leere Except-Handler in früheren Python-Versionen ungültig zu machen.

Ein Werkzeug wird bereitgestellt, um Code automatisch zu aktualisieren und leere except: durch except BaseException: zu ersetzen.

Sicherheitsimplikationen

Diese Änderung hat keine sicherheitsrelevanten Auswirkungen.

Wie man das lehrt

Für neue Python-Benutzer sollte die Ausnahmebehandlung von Anfang an mit expliziten Ausnahmetypen gelehrt werden.

try:
    result = risky_operation()
except ValueError:
    handle_value_error()
except TypeError:
    handle_type_error()
except Exception as e:
    handle_unexpected_error(e)

Für erfahrene Benutzer kann die Änderung als Best Practice eingeführt werden, die nun von der Sprache erzwungen wird. Die folgenden Punkte sollten hervorgehoben werden:

  1. Fangen Sie immer spezifische Ausnahmen ab, wenn möglich.
  2. Verwenden Sie except Exception: als letzte Möglichkeit für wirklich unerwartete Fehler.
  3. Unterdrücken Sie niemals Ausnahmen ohne sorgfältige Überlegung.

Die Dokumentation sollte gängige Ausnahmethierarchien und die Wahl geeigneter Ausnahmetypen zum Abfangen anleiten.

Abgelehnte Ideen

  • Es gibt legitime Fälle, in denen die Verwendung leerer except:-Handler korrekt ist. Ein Beispiel, das von Mailman [8] angeführt wurde, betrifft die Handhabung von Transaktionen angesichts jeder Ausnahme.
    @contextmanager
    def transaction():
        """Context manager for ensuring the transaction is complete."""
        try:
            yield
        except:
            config.db.abort()
            raise
        else:
            config.db.commit()
    

    Dieser Code garantiert, dass unabhängig davon, welche Ausnahme auftritt, jede offene Transaktion abgebrochen wird, während unter erfolgreichen Bedingungen die Transaktion committet wird.

    Wir sind der Meinung, dass es, obwohl es Fälle wie diesen gibt, in denen leere except:-Handler korrekt sind, besser wäre, tatsächlich explizit zu sein und except BaseException: aus den in der Sektion „Motivation“ genannten Gründen zu verwenden.


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

Zuletzt geändert: 2025-02-01 07:28:42 GMT