Wie Sie richtig erraten haben, gibt es zwei Seiten: Abfangen eines Fehlers durch Angabe des Ausnahmetyps nach dem Angeben except
und einfaches Übergeben ohne Fehler .
Meine Erklärung ist "ein bisschen" länger - also zerfällt es wie folgt:
- Fange keinen Fehler . Geben Sie immer an, von welchen Ausnahmen Sie sich erholen möchten, und fangen Sie nur diese ab.
- Vermeiden Sie es, außer Blöcken vorbeizukommen . Sofern nicht ausdrücklich gewünscht, ist dies normalerweise kein gutes Zeichen.
Aber gehen wir ins Detail:
Fange keinen Fehler
Wenn Sie einen try
Block verwenden, tun Sie dies normalerweise, weil Sie wissen, dass die Möglichkeit besteht, dass eine Ausnahme ausgelöst wird. Als solches haben Sie auch bereits eine ungefähre Vorstellung davon, was brechen und welche Ausnahme ausgelöst werden kann. In solchen Fällen fangen Sie eine Ausnahme ab, weil Sie sich positiv davon erholen können. Das bedeutet, dass Sie auf die Ausnahme vorbereitet sind und einen alternativen Plan haben, dem Sie im Falle dieser Ausnahme folgen werden.
Wenn Sie beispielsweise den Benutzer auffordern, eine Zahl einzugeben, können Sie die Eingabe konvertieren, mit int()
der möglicherweise eine a ausgelöst wird ValueError
. Sie können dies leicht wiederherstellen, indem Sie den Benutzer einfach auffordern, es erneut zu versuchen. ValueError
Daher wäre es ein angemessener Plan , den Benutzer zu fangen und ihn erneut aufzufordern. Ein anderes Beispiel wäre, wenn Sie eine Konfiguration aus einer Datei lesen möchten und diese Datei zufällig nicht vorhanden ist. Da es sich um eine Konfigurationsdatei handelt, haben Sie möglicherweise eine Standardkonfiguration als Fallback, sodass die Datei nicht unbedingt erforderlich ist. Daher FileNotFoundError
wäre es hier ein guter Plan, eine zu erfassen und einfach die Standardkonfiguration anzuwenden. In beiden Fällen haben wir eine sehr spezifische Ausnahme, die wir erwarten, und wir haben einen ebenso spezifischen Plan, um uns davon zu erholen. Als solche haben wir in jedem Fall ausdrücklich nur except
das Bestimmte Ausnahme.
Wenn wir jedoch alles fangen , besteht - zusätzlich zu den Ausnahmen, von denen wir bereit sind, uns zu erholen - auch die Möglichkeit, dass wir Ausnahmen erhalten, die wir nicht erwartet haben und von denen wir uns tatsächlich nicht erholen können. oder sollte sich nicht erholen.
Nehmen wir das Beispiel der Konfigurationsdatei von oben. Im Falle einer fehlenden Datei haben wir gerade unsere Standardkonfiguration angewendet und möglicherweise zu einem späteren Zeitpunkt beschlossen, die Konfiguration automatisch zu speichern (damit die Datei beim nächsten Mal vorhanden ist). Stellen Sie sich jetzt vor, wir bekommen ein IsADirectoryError
oder einPermissionError
stattdessen. In solchen Fällen wollen wir wahrscheinlich nicht weitermachen; Wir könnten weiterhin unsere Standardkonfiguration anwenden, aber später können wir die Datei nicht speichern. Und es ist wahrscheinlich, dass der Benutzer auch eine benutzerdefinierte Konfiguration haben wollte, sodass die Verwendung der Standardwerte wahrscheinlich nicht erwünscht ist. Daher möchten wir den Benutzer sofort darüber informieren und wahrscheinlich auch die Programmausführung abbrechen. Aber das wollen wir nicht irgendwo tief in einem kleinen Codeteil tun. Dies ist von Bedeutung auf Anwendungsebene, daher sollte es oben behandelt werden. Lassen Sie also die Ausnahme in die Luft sprudeln.
Ein weiteres einfaches Beispiel wird auch im Python 2-Redewendungsdokument erwähnt. Hier existiert ein einfacher Tippfehler im Code, der dazu führt, dass er kaputt geht. Weil wir jede Ausnahme abfangen, fangen wir auch NameError
s und SyntaxError
s . Beides sind Fehler, die uns allen beim Programmieren passieren. und beides sind Fehler, die wir beim Versand des Codes unbedingt nicht berücksichtigen möchten. Aber weil wir diese auch gefangen haben, werden wir nicht einmal wissen, dass sie dort aufgetreten sind, und jede Hilfe verlieren, um sie korrekt zu debuggen.
Es gibt aber auch gefährlichere Ausnahmen, auf die wir wahrscheinlich nicht vorbereitet sind. Zum Beispiel ist SystemError normalerweise etwas, das selten vorkommt und das wir nicht wirklich planen können. es bedeutet, dass etwas Komplizierteres vor sich geht, was uns wahrscheinlich daran hindert, die aktuelle Aufgabe fortzusetzen.
In jedem Fall ist es sehr unwahrscheinlich, dass Sie in einem kleinen Teil des Codes auf alles vorbereitet sind. Hier sollten Sie also nur die Ausnahmen abfangen, auf die Sie vorbereitet sind. Einige Leute schlagen vor, zumindest zu fangen, Exception
da es keine Dinge wie SystemExit
und KeyboardInterrupt
die beabsichtigt sind, Ihre Anwendung zu beenden, aber ich würde argumentieren, dass dies immer noch viel zu unspezifisch ist. Es gibt nur einen Ort, an dem ich persönlich das Fangen akzeptiere Exception
oder nur irgendeinenAusnahme, und das ist in einem einzelnen globalen Ausnahmebehandler auf Anwendungsebene, der den einzigen Zweck hat, jede Ausnahme zu protokollieren, auf die wir nicht vorbereitet waren. Auf diese Weise können wir immer noch so viele Informationen über unerwartete Ausnahmen behalten, die wir dann verwenden können, um unseren Code zu erweitern, um diese explizit zu behandeln (wenn wir sie wiederherstellen können) oder - im Fehlerfall - Testfälle zu erstellen, um dies sicherzustellen es wird nicht wieder vorkommen. Aber das funktioniert natürlich nur, wenn wir nur die Ausnahmen erwischt haben, die wir bereits erwartet hatten. Diejenigen, die wir nicht erwartet haben, werden natürlich in die Luft sprudeln.
Vermeiden Sie es, außer Blöcken vorbeizukommen
Wenn wir explizit eine kleine Auswahl spezifischer Ausnahmen abfangen, gibt es viele Situationen, in denen es uns gut geht, wenn wir einfach nichts tun. In solchen Fällen except SomeSpecificException: pass
ist es in Ordnung , nur zu haben . Meistens ist dies jedoch nicht der Fall, da wir wahrscheinlich Code für den Wiederherstellungsprozess benötigen (wie oben erwähnt). Dies kann beispielsweise etwas sein, das die Aktion erneut versucht, oder stattdessen einen Standardwert einrichten.
Wenn dies jedoch nicht der Fall ist, zum Beispiel weil unser Code bereits so strukturiert ist, dass er wiederholt wird, bis er erfolgreich ist, ist es gut genug, nur zu übergeben. In unserem Beispiel von oben möchten wir den Benutzer möglicherweise bitten, eine Nummer einzugeben. Da wir wissen, dass Benutzer nicht gerne das tun, wonach wir sie fragen, setzen wir es möglicherweise zunächst in eine Schleife, sodass es folgendermaßen aussehen kann:
def askForNumber ():
while True:
try:
return int(input('Please enter a number: '))
except ValueError:
pass
Da wir es so lange versuchen, bis keine Ausnahme mehr ausgelöst wird, müssen wir im Ausnahmeblock nichts Besonderes tun. Das ist also in Ordnung. Aber natürlich könnte man argumentieren, dass wir dem Benutzer zumindest eine Fehlermeldung anzeigen möchten, um ihm zu sagen, warum er die Eingabe wiederholen muss.
In vielen anderen Fällen except
ist es jedoch ein Zeichen dafür, dass wir nicht wirklich auf die Ausnahme vorbereitet waren, die wir fangen. Versuchen Sie zu vermeiden, nur zu bestehen, es sei denn, diese Ausnahmen sind einfach (wie ValueError
oder TypeError
) und der Grund, warum wir bestehen können, liegt auf der Hand. Wenn es wirklich nichts zu tun gibt (und Sie sind sich absolut sicher), sollten Sie einen Kommentar hinzufügen, warum dies der Fall ist. Andernfalls erweitern Sie den Ausnahmeblock, um tatsächlich einen Wiederherstellungscode einzuschließen.
except: pass
Der schlimmste Täter ist jedoch die Kombination von beiden. Dies bedeutet , dass wir fangen bereitwillig jeden Fehler , obwohl wir absolut nicht darauf vorbereitet und wir tun auch nichts darüber. Sie möchten den Fehler zumindest protokollieren und ihn wahrscheinlich erneut erhöhen, um die Anwendung trotzdem zu beenden (es ist unwahrscheinlich, dass Sie nach einem MemoryError wie gewohnt fortfahren können). Wenn Sie jedoch nur weitergeben, bleibt die Anwendung nicht nur am Leben (je nachdem, wo Sie sie abfangen), sondern Sie werfen auch alle Informationen weg, sodass der Fehler nicht erkannt werden kann. Dies gilt insbesondere dann, wenn Sie ihn nicht entdecken.
Das Fazit lautet also: Fangen Sie nur Ausnahmen ab, die Sie wirklich erwarten und von denen Sie sich erholen möchten. Bei allen anderen handelt es sich wahrscheinlich entweder um Fehler, die Sie beheben sollten, oder um etwas, auf das Sie ohnehin nicht vorbereitet sind. Das Übergeben bestimmter Ausnahmen ist in Ordnung, wenn Sie wirklich nichts dagegen tun müssen. In allen anderen Fällen ist es nur ein Zeichen von Vermutung und Faulheit. Und das wollen Sie auf jeden Fall beheben.
logging
Modul auf DEBUG-Ebene, um zu vermeiden, dass sie in der Produktion ausströmen, aber halten Sie sie in der Entwicklung verfügbar.