PEP 352 – Erforderliche Oberklasse für Ausnahmen
- Autor:
- Brett Cannon, Guido van Rossum
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 27. Okt. 2005
- Python-Version:
- 2.5
- Post-History:
Zusammenfassung
In Python 2.4 und früher konnte jede (klassische) Klasse als Ausnahme ausgelöst werden. Der Plan für 2.5 war, neue Stilklassen zuzulassen, aber das verschlimmert das Problem – es würde bedeuten, dass *jede* Klasse (oder Instanz) ausgelöst werden kann! Das ist ein Problem, da es verhindert, dass Garantien über die Schnittstelle von Ausnahmen gemacht werden können. Dieses PEP schlägt die Einführung einer neuen Oberklasse vor, von der alle ausgelösten Objekte erben müssen. Die Auferlegung dieser Beschränkung ermöglicht die Existenz einer standardmäßigen Schnittstelle für Ausnahmen, auf die man sich verlassen kann. Sie führt auch zu einer bekannten Hierarchie, an die sich alle Ausnahmen halten müssen.
Man könnte einwenden, dass die Anforderung einer bestimmten Basisklasse für eine bestimmte Schnittstelle un-pythonisch ist. Im speziellen Fall von Ausnahmen gibt es jedoch einen guten Grund (der allgemein auf python-dev zugestimmt wurde): Eine Hierarchie vorzuschreiben, hilft Code, der Ausnahmen *auffangen* möchte, indem es möglich wird, *alle* Ausnahmen explizit aufzufangen, indem man except BaseException: anstelle von except *: schreibt. [1]
Die Einführung einer neuen Oberklasse für Ausnahmen gibt uns auch die Möglichkeit, die Ausnahmehierarchie leicht zum Besseren zu ordnen. Derzeit erben alle Ausnahmen im integrierten Namespace von Exception. Das ist ein Problem, da dies zwei Ausnahmen (KeyboardInterrupt und SystemExit) einschließt, die oft von der Ausnahmebehandlung der Anwendung ausgenommen werden müssen: Das Standardverhalten, den Interpreter ohne Traceback zu beenden, ist normalerweise wünschenswerter als das, was die Anwendung tun könnte (mit der möglichen Ausnahme von Anwendungen, die die interaktive Befehlszeilenschleife von Python mit der Eingabeaufforderung >>> emulieren). Wenn diese beiden Ausnahmen stattdessen von der gemeinsamen Oberklasse anstelle von Exception erben, wird es für die Leute einfach sein, except-Klauseln zu schreiben, die nicht übermäßig umfassend sind und keine Ausnahmen abfangen, die nach oben weitergegeben werden sollten.
Dieses PEP basiert auf früheren Arbeiten für PEP 348.
Eine gemeinsame Oberklasse vorschreiben
Dieses PEP schlägt die Einführung einer neuen Ausnahme namens BaseException vor, die eine neue Stilklasse ist und ein einzelnes Attribut hat: args. Unten sehen Sie den Code, wie die Ausnahme in Python 3.0 funktionieren wird (wie sie in Python 2.x funktionieren wird, wird im Abschnitt Übergangsplan behandelt)
class BaseException(object):
"""Superclass representing the base of the exception hierarchy.
Provides an 'args' attribute that contains all arguments passed
to the constructor. Suggested practice, though, is that only a
single string argument be passed to the constructor.
"""
def __init__(self, *args):
self.args = args
def __str__(self):
if len(self.args) == 1:
return str(self.args[0])
else:
return str(self.args)
def __repr__(self):
return "%s(*%s)" % (self.__class__.__name__, repr(self.args))
Aus Kompatibilitätsgründen werden keine Einschränkungen für das, was für args übergeben werden darf, vorgenommen. In der Praxis sollte jedoch nur ein einzelnes String-Argument verwendet werden. Dies stellt sicher, dass die String-Darstellung der Ausnahme eine nützliche und für Menschen lesbare Nachricht über die Ausnahme ist; deshalb behandelt die Methode __str__ einen args-Wert der Länge 1 speziell. Programmatische Informationen (z. B. eine Fehlercodenummer) sollten in einer Unterklasse als separates Attribut gespeichert werden.
Die raise-Anweisung wird so geändert, dass jedes Objekt, das ihr übergeben wird, von BaseException erben muss. Dies stellt sicher, dass alle Ausnahmen innerhalb einer einzigen Hierarchie fallen, die bei BaseException verankert ist [1]. Dies garantiert auch eine grundlegende Schnittstelle, die von BaseException geerbt wird. Die Änderung an raise wird ab Python 3.0 durchgesetzt (siehe Übergangsplan unten).
Da BaseException die Wurzel der Ausnahmehierarchie ist, wird Exception nun davon erben.
Änderungen der Ausnahmehierarchie
Da die Ausnahmehierarchie jetzt noch wichtiger ist, da sie eine grundlegende Wurzel hat, ist eine Änderung der bestehenden Hierarchie erforderlich. Wie es derzeit ist, wenn man alle Ausnahmen abfangen möchte, die einen Fehler signalisieren *und* nicht bedeuten, dass der Interpreter beendet werden soll, muss man alle außer zwei Ausnahmen speziell in einer except-Klausel angeben oder die beiden Ausnahmen separat abfangen und dann erneut auslösen und alle anderen Ausnahmen in einer leeren except-Klausel durchfallen lassen.
except (KeyboardInterrupt, SystemExit):
raise
except:
...
Das ist unnötig explizit. Dieses PEP schlägt vor, KeyboardInterrupt und SystemExit direkt von BaseException erben zu lassen.
- BaseException
|- KeyboardInterrupt
|- SystemExit
|- Exception
|- (all other current built-in exceptions)
Dadurch wird das Abfangen von Exception sinnvoller. Es würde nur Ausnahmen abfangen, die Fehler signalisieren. Ausnahmen, die signalisieren, dass der Interpreter beendet werden soll, werden nicht abgefangen und somit nach oben weitergegeben, um die Beendigung des Interpreters zu ermöglichen.
KeyboardInterrupt wurde verschoben, da Benutzer typischerweise erwarten, dass eine Anwendung beendet wird, wenn sie die Interrupt-Taste drücken (normalerweise Strg+C). Wenn Personen übermäßig umfassende except-Klauseln haben, tritt das erwartete Verhalten nicht ein.
SystemExit wurde aus ähnlichen Gründen verschoben. Da die Ausnahme ausgelöst wird, wenn sys.exit() aufgerufen wird, sollte dem Interpreter normalerweise erlaubt werden, beendet zu werden. Leider können übermäßig umfassende except-Klauseln die explizit angeforderte Beendigung verhindern.
Um sicherzustellen, dass die Leute meistens Exception abfangen, müssen verschiedene Teile der Dokumentation und Tutorials aktualisiert werden, um dringend nahezulegen, dass Exception das ist, was Programmierer verwenden möchten. Leere except-Klauseln oder das direkte Abfangen von BaseException sollten entmutigt werden, da KeyboardInterrupt und SystemExit fast immer nach oben weitergegeben werden sollten.
Migrationsplan
Da semantische Änderungen an Python vorgeschlagen werden, ist ein Übergangsplan erforderlich. Das Ziel ist, dass die neuen Semantiken in Python 3.0 verwendet werden, während gleichzeitig ein reibungsloser Übergang für 2.x-Code bereitgestellt wird. Alle im Plan erwähnten Deprekationen führen zur Entfernung der Semantiken ab der Version, die auf die anfängliche Deprekation folgt.
Hier ist BaseException, wie sie in der 2.x-Serie implementiert ist
class BaseException(object):
"""Superclass representing the base of the exception hierarchy.
The __getitem__ method is provided for backwards-compatibility
and will be deprecated at some point. The 'message' attribute
is also deprecated.
"""
def __init__(self, *args):
self.args = args
def __str__(self):
return str(self.args[0]
if len(self.args) <= 1
else self.args)
def __repr__(self):
func_args = repr(self.args) if self.args else "()"
return self.__class__.__name__ + func_args
def __getitem__(self, index):
"""Index into arguments passed in during instantiation.
Provided for backwards-compatibility and will be
deprecated.
"""
return self.args[index]
def _get_message(self):
"""Method for 'message' property."""
warnings.warn("the 'message' attribute has been deprecated "
"since Python 2.6")
return self.args[0] if len(args) == 1 else ''
message = property(_get_message,
doc="access the 'message' attribute; "
"deprecated and provided only for "
"backwards-compatibility")
Die Deprekation von Funktionen in Python 2.9 ist optional. Dies liegt daran, dass zum jetzigen Zeitpunkt noch nicht bekannt ist, ob Python 2.9 (das die letzte Version der 2.x-Serie sein soll) Funktionen aktiv deprecaten wird, die nicht in 3.0 enthalten sein werden. Es ist denkbar, dass in 2.9 keine Deprekationswarnungen verwendet werden, da es einen so großen Unterschied zwischen 2.9 und 3.0 geben könnte, dass 2.9 in Bezug auf Warnungen zu „rauschig“ wäre. Daher werden die vorgeschlagenen Deprekationswarnungen für Python 2.9 neu bewertet, wenn die Entwicklung dieser Version beginnt, um festzustellen, ob sie noch gewünscht sind.
- Python 2.5 [erledigt]
- Alle Standardausnahmen werden zu Klassen neuen Stils [erledigt]
- BaseException einführen [erledigt]
- Exception, KeyboardInterrupt und SystemExit erben von BaseException [erledigt]
- String-Ausnahmen deprecaten (sowohl auslösen) [erledigt]
- Python 2.6 [erledigt]
- String-Ausnahmen deprecaten (abfangen) [erledigt]
- Attribut
messagedeprecaten (siehe Verworfene Ideen) [erledigt]
- Python 2.7 [erledigt]
- Ausnahmen deprecaten, die nicht von BaseException erben
- Python 3.0 [erledigt]
- Alles fallen lassen, das oben deprecaten wurde
- String-Ausnahmen (sowohl auslösen als auch abfangen) [erledigt]
- Alle Ausnahmen müssen von BaseException erben [erledigt]
__getitem__,messagefallen lassen [erledigt]
- Alles fallen lassen, das oben deprecaten wurde
Verworfene Ideen
Eine frühere Version dieses PEP, die in Python 2.5 implementiert wurde, enthielt ein 'message'-Attribut auf BaseException. Sein Zweck war es, einen Übergang zu BaseException zu beginnen, das nur ein einziges Argument akzeptiert. Dies diente dazu, die Schnittstelle zu straffen und Leute zu zwingen, Attribute in Unterklassen zu verwenden, um beliebige Informationen mit einer Ausnahme zu übertragen, anstatt alles in args zu quetschen.
Leider wurde während der Implementierung der Entfernung des args-Attributs in Python 3.0 beim PyCon 2007 Sprint [2] festgestellt, dass der Übergang sehr schmerzhaft war, insbesondere für C-Erweiterungsmodule. Es wurde beschlossen, dass es besser wäre, das message-Attribut in Python 2.6 zu deprecaten (und es in Python 2.7 und Python 3.0 zu entfernen) und eine langfristigere Übergangsstrategie in Python 3.0 zu erwägen, um die Unterstützung für mehrere Argumente in BaseException zugunsten der Akzeptanz nur eines Arguments zu entfernen. Daher wurde die Einführung von message und die ursprüngliche Deprekation von args zurückgezogen.
Referenzen
- Issue für neue Stil-Ausnahmen: python/cpython#41459
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0352.rst
Zuletzt geändert: 2024-12-03 18:09:24 GMT