Bei Verwendung der PyCharm-IDE except:
löst die Verwendung von ohne Ausnahmetyp eine Erinnerung von der IDE aus, dass diese Ausnahmeklausel ist Too broad
.
Sollte ich diesen Rat ignorieren? Oder ist es pythonisch, immer den Ausnahmetyp anzugeben?
Bei Verwendung der PyCharm-IDE except:
löst die Verwendung von ohne Ausnahmetyp eine Erinnerung von der IDE aus, dass diese Ausnahmeklausel ist Too broad
.
Sollte ich diesen Rat ignorieren? Oder ist es pythonisch, immer den Ausnahmetyp anzugeben?
Antworten:
Es ist fast immer besser, einen expliziten Ausnahmetyp anzugeben. Wenn Sie eine nackte except:
Klausel verwenden, werden möglicherweise andere Ausnahmen als die erwarteten abgefangen. Dies kann Fehler verbergen oder das Debuggen von Programmen erschweren, wenn sie nicht das tun, was Sie erwarten.
Wenn Sie beispielsweise eine Zeile in eine Datenbank einfügen, möchten Sie möglicherweise eine Ausnahme abfangen, die angibt, dass die Zeile bereits vorhanden ist, damit Sie eine Aktualisierung durchführen können.
try:
insert(connection, data)
except:
update(connection, data)
Wenn Sie ein Bare angeben except:
, wird auch ein Socket-Fehler angezeigt, der darauf hinweist, dass der Datenbankserver umgefallen ist. Es ist am besten, nur Ausnahmen abzufangen, mit denen Sie umgehen können. Oft ist es besser, wenn das Programm zum Zeitpunkt der Ausnahme fehlschlägt, als fortzufahren, sich aber auf seltsame, unerwartete Weise zu verhalten.
Ein Fall, in dem Sie möglicherweise ein Bare verwenden möchten, except:
befindet sich auf der obersten Ebene eines Programms, das Sie immer ausführen müssen, z. B. eines Netzwerkservers. Aber dann müssen Sie sehr vorsichtig sein, um die Ausnahmen zu protokollieren, sonst ist es unmöglich herauszufinden, was falsch läuft. Grundsätzlich sollte es in einem Programm höchstens einen Ort geben, der dies tut.
Eine logische Folge all dessen ist , dass Ihr Code sollte nie tun , raise Exception('some message')
weil es Client - Code zu verwenden zwingt except:
(oder except Exception:
das ist fast so schlimm). Sie sollten eine Ausnahme definieren, die für das Problem spezifisch ist, das Sie signalisieren möchten (möglicherweise von einer integrierten Ausnahmeunterklasse wie ValueError
oder erben TypeError
). Oder Sie sollten eine bestimmte integrierte Ausnahme auslösen. Auf diese Weise können Benutzer Ihres Codes vorsichtig sein, wenn sie nur die Ausnahmen abfangen, die sie behandeln möchten.
except:
fängt auch (unter anderem) NameError
und AttributeError
wenn Sie also etwas im try
Block falsch schreiben (z. B. wird Ihre "Einfügen" -Funktion tatsächlich aufgerufen, insert_one
weil jemand die Konsistenz nicht so sehr schätzte, wie er sollte), es versucht immer still zu update()
.
main()
)?
except Exception:
wird fangen NameError
und AttributeError
auch. Was Bare except:
so schlecht macht , ist, dass es Dinge fängt, die kein Geschäft haben, z. B. SystemExit
(ausgelöst, wenn Sie anrufen exit
oder sys.exit
, und jetzt haben Sie einen beabsichtigten Exit verhindert) und KeyboardInterrupt
(wieder, wenn der Benutzer trifft Ctrl-C
, möchten Sie wahrscheinlich nicht weiterlaufen, nur um sie zu ärgern). Nur letzteres macht wirklich Sinn zu fangen, und es sollte explizit gefangen werden. Zumindest except Exception:
lassen sich diese beiden normal ausbreiten.
Sie sollten den Rat des Dolmetschers nicht ignorieren.
Aus dem PEP-8 Style Guide für Python:
Erwähnen Sie beim Abfangen von Ausnahmen nach Möglichkeit bestimmte Ausnahmen, anstatt eine bloße Ausnahme: -Klausel zu verwenden.
Verwenden Sie zum Beispiel:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
Eine bloße Ausnahme: -Klausel fängt SystemExit- und KeyboardInterrupt-Ausnahmen ab, was es schwieriger macht, ein Programm mit Control-C zu unterbrechen, und kann andere Probleme verschleiern. Wenn Sie alle Ausnahmen abfangen möchten, die Programmfehler signalisieren, verwenden Sie außer Ausnahme: (nackte Ausnahme entspricht Ausnahme BaseException :).
Eine gute Faustregel besteht darin, die Verwendung von bloßen Ausnahmeklauseln auf zwei Fälle zu beschränken:
Wenn der Ausnahmebehandler den Traceback ausdrucken oder protokollieren wird; Zumindest wird dem Benutzer bekannt sein, dass ein Fehler aufgetreten ist. Wenn der Code einige Bereinigungsarbeiten ausführen muss, die Ausnahme dann jedoch mit Raise nach oben übertragen wird. versuchen Sie ... endlich kann ein besserer Weg sein, um diesen Fall zu behandeln.
Nicht spezifisch für Python.
Der springende Punkt bei Ausnahmen ist, das Problem so nahe wie möglich an der Stelle zu behandeln, an der es verursacht wurde.
Sie behalten also den Code, der unter außergewöhnlichen Umständen das Problem und die Auflösung "nebeneinander" auslösen könnte.
Die Sache ist, dass Sie nicht alle Ausnahmen kennen können, die von einem Code ausgelöst werden könnten. Alles, was Sie wissen können, ist, dass Sie, wenn es sich um eine Ausnahme handelt, bei der eine Datei nicht gefunden wurde, diese abfangen und den Benutzer auffordern können, eine Ausnahme zu erhalten, die die Funktion ausführt oder abbricht.
Wenn Sie versuchen, das zu umgehen, wird unabhängig davon, welches Problem in Ihrer Dateiroutine aufgetreten ist (schreibgeschützt, Berechtigungen, Benutzerkontensteuerung, nicht wirklich ein PDF usw.), jeder in Ihre Datei gefunden, der nicht gefunden wurde, und Ihr Benutzer schreit "aber es ist da, dieser Code ist Mist"
Jetzt gibt es einige Situationen, in denen Sie vielleicht alles fangen, aber sie sollten bewusst ausgewählt werden.
Sie werden abgefangen, machen eine lokale Aktion rückgängig (z. B. das Erstellen oder Sperren einer Ressource (Öffnen einer Datei zum Schreiben zum Schreiben), dann lösen Sie die Ausnahme erneut aus, um sie auf einer höheren Ebene zu behandeln).
Dem anderen ist es egal, warum es schief gelaufen ist. Zum Beispiel drucken. Möglicherweise haben Sie einen Haken, der besagt, dass es ein Problem mit Ihrem Drucker gibt. Bitte klären Sie es und beenden Sie die Anwendung nicht deswegen. Ähnlich vergeblich, wenn Ihr Code eine Reihe separater Aufgaben nach einem Zeitplan ausführt, möchten Sie nicht, dass das Ganze stirbt, da eine der Aufgaben fehlgeschlagen ist.
Hinweis Wenn Sie die oben genannten Schritte ausführen, kann ich keine Ausnahmeprotokollierung empfehlen, z. B. versuchen Sie, das Ende des Fangprotokolls hoch genug zu ermitteln.
Sie werden damit auch zB Control-C fangen, also tun Sie es nicht, es sei denn, Sie "werfen" es erneut. In diesem Fall sollten Sie jedoch lieber "finally" verwenden.
Immer geben Sie den Ausnahmetyp, gibt es viele Typen , die Sie nicht fangen wollen, wie SyntaxError
, KeyboardInterrupt
, MemoryError
usw.
except Exception:
die oben genannten Typen vermeiden, die wir nicht fangen wollen?
except Exception
ist gut.
except Exception
fängt SyntaxError
und MemoryError
weil es ihre Basisklasse ist. KeyboardInterrupt
, SystemExit
( sys.exit()
ausgelöst von ) werden nicht abgefangen (es handelt sich um unmittelbare BaseException-Unterklassen)
Hier sind die Orte, an denen ich außer ohne Typ benutze
Das ist die Hauptverwendung in meinem Code für ungeprüfte Ausnahmen
Ich füge dies immer hinzu, damit der Produktionscode keine Stapelspuren verschüttet
Ich habe zwei Möglichkeiten:
Ich bevorzuge es so, ich finde es einfacher zu erkennen, welche Ausnahmen angemessen abgefangen werden sollten: Ich "sehe" das Problem besser, wenn eine Ausnahme niedrigerer Ebene von einer höheren Ebene protokolliert wird
Einige Mitarbeiter bevorzugen diesen Weg, da Ausnahmen auf niedrigerer Ebene in Funktionen auf niedrigerer Ebene beibehalten werden, zu denen sie "gehören".