PEP 473 – Hinzufügen strukturierter Daten zu eingebauten Ausnahmen
- Autor:
- Sebastian Kreft <skreft at deezer.com>
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 29-Mär-2014
- Post-History:
- Resolution:
- Python-Dev Nachricht
Zusammenfassung
Ausnahmen wie AttributeError, IndexError, KeyError, LookupError, NameError, TypeError und ValueError bieten nicht alle Informationen, die Programmierer benötigen, um zu debuggen und besser zu verstehen, was sie verursacht hat. Darüber hinaus haben die Meldungen in einigen Fällen sogar leicht unterschiedliche Formate, was es für Werkzeuge sehr schwierig macht, automatisch zusätzliche Informationen zur Diagnose des Problems bereitzustellen. Um ersteres zu lösen und die Grundlage für letzteres zu schaffen, wird vorgeschlagen, diese Ausnahmen zu erweitern, damit sie sowohl die beleidigenden als auch die betroffenen Entitäten enthalten.
Begründung
Das Hauptproblem, das dieser PEP lösen soll, ist die Tatsache, dass Fehlermeldungen derzeit nicht sehr aussagekräftig sind und wichtige Informationen zur Behebung der Ausnahmen fehlen. Zusätzlich ist die in der Fehlermeldung vorhandene Information nicht immer im gleichen Format, was es für Drittanbieterbibliotheken sehr schwierig macht, eine automatisierte Diagnose des Fehlers bereitzustellen.
Diese automatisierten Werkzeuge könnten beispielsweise Tippfehler erkennen oder zusätzliche Debugging-Informationen anzeigen oder protokollieren. Dies könnte besonders nützlich sein, wenn Tests ausgeführt werden oder in einer lang laufenden Anwendung.
Obwohl es theoretisch möglich ist, solche Bibliotheken zu haben, müssen sie zu Hacks greifen, um das Ziel zu erreichen. Ein Beispiel dafür ist python-improved-exceptions [1], das den Bytecode modifiziert, um Referenzen auf möglicherweise interessante Objekte zu speichern und auch die Fehlermeldungen parst, um Informationen wie Typen oder Namen zu extrahieren. Leider ist ein solcher Ansatz extrem fragil und nicht portabel.
Ein ähnlicher Vorschlag [2] wurde für ImportError implementiert und in gleicher Weise hat diese Idee Unterstützung erhalten [3]. Zusätzlich hat Guido vor fast 10 Jahren in [11] nach einer sauberen API gefragt, um auf die betroffenen Objekte in Ausnahmen wie KeyError, AttributeError, NameError und IndexError zuzugreifen. Ähnliche Probleme und Vorschläge wurden im letzten Jahr verfasst. Einige andere Probleme wurden erstellt, aber trotz erhaltener Unterstützung schließlich aufgegeben. Referenzen auf die erstellten Probleme sind unten aufgeführt
AttributeError: [11], [10], [5], [4], [3]IndexError: [11], [6], [3]KeyError: [11], [7], [3]LookupError: [11]NameError: [11], [10], [3]TypeError: [8]ValueError: [9]
Um mit der Entwicklung fortzufahren und die Informationen und Diskussionen zu zentralisieren, zielt diese PEP darauf ab, eine Meta-Ausgabe zu sein, die alle oben genannten Diskussionen und Ideen zusammenfasst.
Beispiele
IndexError
Die Fehlermeldung referenziert weder die Länge der Liste noch den verwendeten Index.
a = [1, 2, 3, 4, 5]
a[5]
IndexError: list index out of range
KeyError
Konventionell ist der Schlüssel das erste Element des Argumentes des Fehlers, aber es gibt keine weiteren Informationen bezüglich des betroffenen Wörterbuchs (Schlüsseltypen, Größe usw.).
b = {'foo': 1}
b['fo']
KeyError: 'fo'
AttributeError
Der Typ des Objekts und das beleidigende Attribut sind Teil der Fehlermeldung. Es gibt jedoch einige unterschiedliche Formate und die Informationen sind nicht immer verfügbar. Darüber hinaus ist, obwohl der Objekttyp in einigen Fällen nützlich ist, angesichts der dynamischen Natur von Python, eine Referenz auf das Objekt selbst viel nützlicher. Zusätzlich ist die Referenz auf den Typ nicht vollständig qualifiziert und in einigen Fällen ist der Typ zu generisch, um nützliche Informationen zu liefern, zum Beispiel beim Zugriff auf ein Attribut eines Moduls.
c = object()
c.foo
AttributeError: 'object' object has no attribute 'foo'
import string
string.foo
AttributeError: 'module' object has no attribute 'foo'
a = string.Formatter()
a.foo
AttributeError: 'Formatter' object has no attribute 'foo'
NameError
Die Fehlermeldung liefert typischerweise den Namen.
foo = 1
fo
NameError: global name 'fo' is not defined
Andere Fälle
Probleme sind noch schwieriger zu debuggen, wenn das Zielobjekt das Ergebnis eines anderen Ausdrucks ist, zum Beispiel
a[b[c[0]]]
Dieses Problem hängt auch damit zusammen, dass Opcodes nur Zeilennummerinformationen und keinen Offset haben. Dieser Vorschlag würde in diesem Fall helfen, aber nicht so sehr wie das Vorhandensein von Offsets.
Vorschlag
Erweitern Sie die Ausnahmen AttributeError, IndexError, KeyError, LookupError, NameError, TypeError und ValueError mit den folgenden
AttributeError: target w, attributeIndexError: target w, key w, index (nur ein Alias für key)KeyError: target w, key wLookupError: target w, key wNameError: name, scope?TypeError: unexpected_typeValueError: unexpected_value w
Attribute mit dem Superscript w benötigen möglicherweise Weak References [12], um Speicherzyklen zu verhindern. Dies kann jedoch unnötige zusätzliche Komplexität hinzufügen, wie von R. David Murray [13] bemerkt. Dies gilt insbesondere, da eingebaute Typen keine Weak References unterstützen.
TODO(skreft): mit Beispielen für Randfälle erweitern.
Um die Abwärtskompatibilität zu gewährleisten, werden diese neuen Attribute optional und nur als Schlüsselwortargumente sein.
Es wird vorgeschlagen, diese Informationen hinzuzufügen, anstatt nur die Fehlermeldung zu verbessern, da ersteres neue Debugging-Frameworks und -Tools ermöglichen und zukünftig auch auf eine Lazy-Message-Generierung umstellen würde. Generierte Meldungen werden in [2] diskutiert, obwohl sie derzeit nicht implementiert sind. Sie würden nicht nur Ressourcen sparen, sondern auch die Meldungen vereinheitlichen.
Die Standardbibliothek wird dann schrittweise geändert, um diese neuen Attribute zu nutzen.
Potenzielle Verwendungen
Ein automatisiertes Werkzeug könnte beispielsweise nach ähnlichen Schlüsseln innerhalb des Objekts suchen und Folgendes anzeigen:
a = {'foo': 1}
a['fo']
KeyError: 'fo'. Did you mean 'foo'?
foo = 1
fo
NameError: global name 'fo' is not defined. Did you mean 'foo'?
Siehe [3] für die Ausgabe, die ein TestRunner anzeigen könnte.
Performance
Das Füllen dieser neuen Attribute erfordert nur zwei zusätzliche Parameter mit bereits verfügbaren Daten, sodass die Auswirkungen marginal sein sollten. Dies erfordert jedoch möglicherweise besondere Vorsicht bei KeyError, da das folgende Muster bereits weit verbreitet ist.
try:
a[foo] = a[foo] + 1
except:
a[foo] = 0
Beachten Sie auch, dass die Speicherung dieser Objekte in der Ausnahme selbst die verzögerte Erzeugung der Fehlermeldung ermöglichen würde, wie in [2] diskutiert.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0473.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT