it-swarm.com.de

Python: `Wenn Key in Dict` vs.` Try/Except`?

Ich habe eine Frage zu Redewendungen und Lesbarkeit, und für diesen speziellen Fall scheint es einen Konflikt zwischen Python-Philosophien zu geben:

Ich möchte Wörterbuch A aus Wörterbuch B erstellen. Wenn ein bestimmter Schlüssel in B nicht vorhanden ist, machen Sie nichts und fahren Sie fort.

Welcher Weg ist besser?

try:
    A["blah"] = B["blah"]
except KeyError:
    pass

oder 

if "blah" in B:
    A["blah"] = B["blah"]

"Mach und bitte um Vergebung" vs. "Einfachheit und Erklärungskraft".

Welches ist besser und warum?

77
LeeMobile

Ausnahmen sind keine Bedingungen.

Die bedingte Version ist klarer. Das ist natürlich: Dies ist eine unkomplizierte Flusskontrolle, wofür Conditionals konzipiert sind, keine Ausnahmen.

Die Ausnahmeversion wird hauptsächlich als Optimierung für diese Suchvorgänge in einer Schleife verwendet: Bei einigen Algorithmen können Tests aus inneren Schleifen entfernt werden. Es hat diesen Vorteil hier nicht. Es hat den kleinen Vorteil, dass es nicht erforderlich ist, "blah" zweimal zu sagen, aber wenn Sie viele davon machen, sollten Sie wahrscheinlich eine move_key-Funktion haben.

Im Allgemeinen empfehle ich dringend, standardmäßig bei der bedingten Version zu bleiben, es sei denn, Sie haben einen bestimmten Grund. Bedingungen sind der naheliegende Weg, dies zu tun, was in der Regel eine starke Empfehlung ist, eine Lösung einer anderen vorzuziehen.

60
Glenn Maynard

Es gibt auch einen dritten Weg, der sowohl Ausnahmen als auch eine doppelte Suche vermeidet, was wichtig sein kann, wenn die Suche teuer ist:

value = B.get("blah", None)
if value is None: 
    A["blah"] = value

Wenn Sie erwarten, dass das Wörterbuch None-Werte enthält, können Sie weitere esoterische Konstanten wie NotImplemented, Ellipsis verwenden oder eine neue erstellen:

MyConst = object()
def update_key(A, B, key):
    value = B.get(key, MyConst)
    if value is not MyConst: 
        A[key] = value

Jedenfalls ist update() die für mich lesbarste Option:

a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b)
45
lqc

Nach meinem Verständnis möchten Sie das Diktier A mit Schlüsselpaaren aus Diktat B aktualisieren

update ist eine bessere Wahl.

A.update(B)

Beispiel:

>>> A = {'a':1, 'b': 2, 'c':3}
>>> B = {'d': 2, 'b':5, 'c': 4}
>>> A.update(B)
>>> A
{'a': 1, 'c': 4, 'b': 5, 'd': 2}
>>> 
14
pyfunc

Direktes Zitat aus dem Python-Performance-Wiki:

Mit Ausnahme des ersten Males schlägt der Test der if-Anweisung jedes Mal fehl, wenn ein Word angezeigt wird. Wenn Sie eine große Anzahl von Wörtern zählen, werden viele wahrscheinlich mehrmals vorkommen. In einer Situation, in der die Initialisierung eines Werts nur einmal vorkommt und die Erhöhung dieses Werts oftmals auftritt, ist die Verwendung einer try-Anweisung billiger.

Es scheint also, dass beide Optionen abhängig von der Situation möglich sind. Für weitere Informationen können Sie diesen Link auschecken: Try-except-performance

6
Sami Lehtinen

Ich denke, die allgemeine Regel hier ist: Will A["blah"] normalerweise existieren, wenn ja try-except gut ist wenn nicht, dann if "blah" in b:

Ich denke "try" ist zeitlich günstig, aber "außer" ist teurer.

3
neil

Ich denke, das zweite Beispiel ist, was Sie tun sollten, wenn dieser Code keinen Sinn macht:

try:
    A["foo"] = B["foo"]
    A["bar"] = B["bar"]
    A["baz"] = B["baz"]
except KeyError:
    pass

Beachten Sie, dass der Code abgebrochen wird, sobald ein Schlüssel in B vorhanden ist. Wenn dieser Code sinnvoll ist, sollten Sie die Ausnahmemethode verwenden, andernfalls verwenden Sie die Testmethode. Meiner Meinung nach ist sie, weil sie kürzer ist und die Absicht klar ausdrückt, viel einfacher zu lesen als die Ausnahmemethode.

Natürlich sind die Leute, die Ihnen sagen, dass Sie update verwenden sollen, korrekt. Wenn Sie eine Version von Python verwenden, die Wörterbuchverstehen unterstützt, würde ich diesen Code unbedingt bevorzugen:

updateset = {'foo', 'bar', 'baz'}
A.update({k: B[k] for k in updateset if k in B})
3
Omnifarious

In anderen Sprachen gilt die Regel, Ausnahmen für außergewöhnliche Bedingungen, d. Ich weiß nicht, wie diese Regel für Python gilt, da StopIteration nach dieser Regel nicht existieren sollte.

2
Mark Ransom

Ich persönlich neige zur zweiten Methode (aber mit has_key):

if B.has_key("blah"):
  A["blah"] = B["blah"]

Auf diese Weise besteht jeder Zuweisungsvorgang nur aus zwei Zeilen (anstelle von 4 mit try/except), und alle Ausnahmen, die ausgelöst werden, sind echte Fehler oder Dinge, die Sie übersehen haben (anstatt nur auf Schlüssel zuzugreifen, die nicht vorhanden sind) .

Wie sich herausstellt (siehe die Kommentare zu Ihrer Frage), ist has_key veraltet - ich denke, es ist besser als geschrieben

if "blah" in B:
  A["blah"] = B["blah"]
1
girasquid

Warum nicht einfach das tun:

def try_except(x,col):
    try:
        return x[col]
    except:
        return None

list(map(lambda x: try_except(x,'blah'),A))
0
Nico Coallier

Ab Python 3.8 und der Einführung von Zuweisungsausdrücken (PEP 572) (Operator :=) können wir den Bedingungswert dictB.get('hello', None) in einer Variablen value erfassen, um zu prüfen, ob es sich nicht um eine None handelt (da dict.get('hello', None) entweder den zugehörigen Wert zurückgibt) oder None) und benutze es dann im Körper der Bedingung:

# dictB = {'hello': 5, 'world': 42}
# dictA = {}
if value := dictB.get('hello', None):
  dictA["hello"] = value
# dictA is now {'hello': 5}
0
Xavier Guihot