Dies ist weniger eine Frage der Art der Ententypisierung als vielmehr der Frage, ob man pythonisch bleibt, nehme ich an.
Zuallererst - wenn es um Dikte geht, insbesondere wenn die Struktur des Diktats ziemlich vorhersehbar ist und ein bestimmter Schlüssel normalerweise nicht vorhanden ist, manchmal aber vorhanden ist, denke ich zuerst an zwei Ansätze:
if myKey in dict:
do_some_work(dict[myKey])
else:
pass
Und natürlich Ye Olde 'Vergebung gegen Erlaubnis' Ansatz.
try:
do_some_work(dict[myKey])
except KeyError:
pass
Als ein geselliger Python-Typ habe ich das Gefühl, dass ich sehe, dass Letzterer viel bevorzugt wird, was sich wohl nur seltsam anfühlt, weil die Python-Dokumente try/excepts
bevorzugt zu sein scheinen, wenn ein tatsächlicher Fehler vorliegt, im Gegensatz zu einem, ähm, fehlenden Erfolg?
Wenn das gelegentliche Diktat keinen Schlüssel in myDict hat und bekannt ist , dass es diesen Schlüssel nicht immer hat, ist ein Versuch / außer in Bezug auf den Kontext irreführend? Dies ist kein Programmierfehler, es ist nur eine Tatsache der Daten - dieses Diktat hatte nur diesen bestimmten Schlüssel nicht.
Dies scheint besonders wichtig zu sein, wenn Sie sich die try / except / else-Syntax ansehen, die sehr nützlich ist, um sicherzustellen, dass try nicht zu viele Fehler abfängt. Sie können Folgendes tun:
try:
foo += bar
except TypeError:
pass
else:
return some_more_work(foo)
Wird das nicht dazu führen, dass alle möglichen seltsamen Fehler verschluckt werden, die wahrscheinlich auf einen schlechten Code zurückzuführen sind? Der obige Code verhindert möglicherweise, dass Sie sehen, dass Sie versuchen, etwas hinzuzufügen, 2 + {}
und Sie werden möglicherweise nie bemerken, dass ein Teil Ihres Codes fürchterlich schief gelaufen ist. Ich schlage nicht vor, dass wir All The Types überprüfen, deshalb ist es Python und nicht JavaScript - aber auch im Kontext von try / except scheint es so, als ob es das Programm dazu bringen soll, etwas zu tun, was es nicht tun sollte, stattdessen zu ermöglichen, weiterzumachen.
Mir ist klar, dass das obige Beispiel so etwas wie ein Strohmann-Argument ist und tatsächlich absichtlich schlecht ist. Aber angesichts des pythonischen Glaubens better to ask forgiveness than permission
kann ich nicht anders, als das Gefühl zu haben, dass sich die Frage stellt, wo die Grenze zwischen der korrekten Anwendung von if / else und try / except liegt, insbesondere wenn Sie wissen, was Sie erwartet die Daten, mit denen Sie arbeiten.
Ich spreche hier nicht einmal von Geschwindigkeitsproblemen oder Best Practices. Ich bin nur ein bisschen verwirrt von dem Venn-Diagramm, in dem es so aussieht, als ob es in beide Richtungen gehen könnte, aber die Leute irren sich auf der Seite eines Versuchs / einer Ausnahme weil 'irgendwo jemand gesagt hat, es sei Pythonic'. Habe ich falsche Schlussfolgerungen bezüglich der Anwendung dieser Syntax gezogen?
Antworten:
Verwenden Sie stattdessen die Methode get :
... wo
default_value
wird der Wert zurückgegeben, wennthe_key
nicht insome_dict
. Wenn Sie weglassendefault_value
,None
wird zurückgegeben, wenn der Schlüssel fehlt.In der Regel bevorzugen die Benutzer in Python eher try / except als zuerst etwas zu überprüfen - siehe den EAFP- Eintrag im Glossar . Beachten Sie, dass viele Funktionen zum Testen der Mitgliedschaft Ausnahmen hinter den Kulissen verwenden.
quelle
dict
und die Arbeit auf der Grundlage der gefundenenif myDict.get(a_key) is not None: do_work(myDict[a_key])
Informationen zu erledigen , fühlt es sich wortreicher an und ist ein weiteres Beispiel für implizites Hinschauen vor dem Sprung. Außerdem ist es meiner Meinung nach etwas weniger lesbar. Vielleicht verstehe ich das nichtdict.get(a_key, a_default)
im richtigen Kontext, aber es scheint ein Vorläufer für das Schreiben von 'not-a-switch-statement if / elses' oder magischen Werten zu sein. Ich mag, was diese Methode tut, ich werde es tiefer untersuchen.data = myDict.get(a_key, default)
und entwederdo_work
tun Sie das Richtige, wenn es Ihnen gegeben wirddefault
(z. B.None
), oder Sie tun esif data: do_work(data)
. In beiden Fällen ist nur eine Suche erforderlich. (if data is not None: ...
In beiden Fällen ist es möglicherweise immer noch nur eine Suche, und dann kann Ihre eigene Logik dietry/except/else
Müll beseitigt und meiner Meinung nach die Lesbarkeit meines Codes insgesamt verbessert. Ich habe eine wertvolle Lektion gelernt, die ich zuvor gehört hatte, die ich aber vernachlässigt habe: "Wenn Sie das Gefühl haben, zu viel Code zu schreiben, hören Sie auf und schauen Sie sich die Sprachfunktionen an." Vielen Dank!!Ist ein fehlender Schlüssel eine Regel oder eine Ausnahme ?
Aus pragmatischer Sicht ist das Werfen / Fangen viel langsamer als das Überprüfen, ob der Schlüssel in der Tabelle ist. Wenn das Fehlen eines Schlüssels häufig vorkommt, sollten Sie die Bedingung verwenden.
Ein weiterer Vorteil von condition ist eine else- Klausel - es ist viel einfacher zu verstehen, wann ein Block ausgeführt wird, wenn berücksichtigt wird, dass dieselbe Ausnahmeklasse aus mehreren Anweisungen im try-Block geworfen werden kann.
Der Code in der except- Klausel sollte nicht Teil des normalen Fehlers sein (z. B. wenn der Schlüssel nicht vorhanden ist, fügen Sie ihn hinzu) - er sollte den Fehler behandeln.
quelle
try
/catch
-Version schneller ausführen.Im Geiste des "pythonischen" und insbesondere des "Enten-Tippens" erscheint mir das try / except fast zerbrechlich.
Alles, was Sie wirklich wollen, ist etwas mit diktatartigem Zugriff, das jedoch
__getitem__
überschrieben werden kann, um etwas zu tun, das nicht ganz Ihren Erwartungen entspricht. Beispieldefaultdict
aus der Standardbibliothek:Da der Standard-Rückgabewert Falsy ist, funktioniert eine solche Zugriffskontrolle die meiste Zeit einwandfrei. Der Code scheint auch einfacher zu sein, weshalb meine Mitarbeiter und ich das seit Monaten getan haben.
Leider führten diese zusätzlichen Schlüssel einige Monate später tatsächlich zu Problemen und schwer auffindbaren Fehlern, da sie
0
zu einem gültigen Wert wurden. Und manchmal wir würden verwendenin
um zu überprüfen , ob ein Schlüssel vorhanden, so dass der Code verschiedene Dinge tun , wenn es identisch sein sollte.Ich schlage vor, dass es kaputt aussieht, weil in Pythons Geist des Entenschreibens alles, was Sie wollen sollten, etwas Diktatartiges ist und
defaultdict
genau zu dieser Anforderung passt, wie jedes Objekt, von dem Sie möglicherweise erbendict
. Sie können nicht garantieren, dass der Anrufer die Implementierung später nicht ändern wird, also sollten Sie das mit den geringsten Nebenwirkungen tun.Verwenden Sie die erste Version
if myKey in mydict
.Beachten Sie auch, dass es sich hierbei speziell um das Beispiel in der Frage handelt. Das Python-Credo "Besser um Vergebung als um Erlaubnis bitten" soll vor allem sicherstellen, dass Sie tatsächlich richtig handeln, wenn Sie nicht das bekommen, was Sie wollen. Wenn Sie beispielsweise prüfen, ob eine Datei vorhanden ist, und dann versuchen, sie zu lesen, können mindestens drei Dinge schief gehen:
Das erste, bei dem Sie versuchen können, "um Erlaubnis zu bitten", aber aufgrund der Rennbedingungen würde es nicht immer funktionieren. der zweite ist zu leicht zu vergessen zu überprüfen; und die dritte kann nicht überprüft werden, ohne zu versuchen, die Datei zu lesen. In jedem Fall wird das, was Sie nach dem Fehlschlagen tun, mit ziemlicher Sicherheit das gleiche sein. In diesem Beispiel ist es daher besser, mit try / except um Verzeihung zu bitten.
quelle