1154 Stimmen

Warum dict.get(Schlüssel) anstelle von dict[Schlüssel]?

Heute bin ich auf die dict Methode get die bei Angabe eines Schlüssels im Wörterbuch den zugehörigen Wert zurückgibt.

Für welchen Zweck ist diese Funktion nützlich? Wenn ich einen Wert finden möchte, der einem Schlüssel in einem Wörterbuch zugeordnet ist, kann ich einfach Folgendes tun dict[key] und erhält dasselbe Ergebnis:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")

21voto

hackartist Punkte 5088

Der Zweck ist, dass Sie einen Standardwert angeben können, wenn der Schlüssel nicht gefunden wird, was sehr nützlich ist

dictionary.get("Name",'harry')

12voto

jetpack_guy Punkte 350

Für welchen Zweck ist diese Funktion nützlich?

Eine besondere Verwendung ist das Zählen mit einem Wörterbuch. Nehmen wir an, Sie wollen die Anzahl der Vorkommen der einzelnen Elemente in einer gegebenen Liste zählen. Die übliche Vorgehensweise besteht darin, ein Wörterbuch zu erstellen, dessen Schlüssel die Elemente und dessen Werte die Anzahl der Vorkommen sind.

fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
    if fruit not in d:
        d[fruit] = 0
    d[fruit] += 1

Die Verwendung des .get() Methode können Sie diesen Code kompakter und übersichtlicher gestalten:

for fruit in fruits:
    d[fruit] = d.get(fruit, 0) + 1

12voto

ggorlen Punkte 32765

Andere antwortet haben den Unterschied zwischen der Diktatklammertastung und der .get y erwähnt eine Ziemlich unverfänglicher Fallstrick wenn None oder der Standardwert ist ebenfalls ein gültiger Schlüssel.

Angesichts dieser Informationen könnte man zu dem Schluss kommen, dass .get ist in gewisser Weise sicherer und besser als die Klammerindizierung und sollte immer anstelle von Klammernachschlagewerken verwendet werden, wie in Keine eckigen Klammern mehr verwenden, um den Wert eines Dictionarys in Python zu ermitteln selbst in dem üblichen Fall, in dem sie erwarten, dass die Suche erfolgreich ist (d. h., sie lösen niemals eine KeyError ).

Der Autor des Blogbeitrags argumentiert, dass .get "schützt Ihren Code":

Beachten Sie, dass der Versuch, einen Begriff zu referenzieren, der nicht existiert, eine KeyError . Dies kann zu erheblichen Problemen führen, insbesondere wenn es um unvorhersehbare Geschäftsdaten geht.

Wir könnten unsere Aussage zwar in eine try / except o if Aussage, so viel Sorgfalt für einen Wörterbuchbegriff wird sich schnell anhäufen.

Es stimmt, dass in dem seltenen Fall, dass null ( None )-Koaleszenz oder anderweitiges Auffüllen eines fehlenden Wertes, um mit unvorhersehbaren dynamischen Daten umzugehen, ein mit Bedacht eingesetzter .get ist ein nützliches und pythonisches Abkürzungswerkzeug für unhandliche if key in dct: y try / except Blöcke, die nur dazu da sind, Standardwerte zu setzen, wenn der Schlüssel als Teil der Verhaltensspezifikation für das Programm fehlen könnte.

Das Ersetzen von alle Klammern Sie diktierte Suchvorgänge, einschließlich derer, von denen Sie behaupten, dass sie erfolgreich sein müssen, mit .get ist eine andere Sache. Diese Praxis degradiert eine Klasse von Laufzeitfehler die dazu beitragen, Fehler in stillen illegalen Zustandsszenarien aufzudecken, die in der Regel schwieriger zu identifizieren und zu debuggen sind.

Ein häufiger Fehler unter Programmierern ist es, Ausnahmen für verursachen Kopfschmerzen und versuchen, sie zu unterdrücken, indem sie Techniken wie die Einbettung von Code in try ... except: pass Blöcke . Später erkennen sie die real Kopfzerbrechen bereitet der Bruch der Anwendungslogik an der Fehlerstelle und die Bereitstellung einer fehlerhaften Anwendung. Eine bessere Programmierpraxis ist die Verwendung von Assertions für alle Programminvarianten, z. B. für Schlüssel, die in einem Wörterbuch enthalten sein müssen.

Die Hierarchie der Fehlersicherheit lautet im Großen und Ganzen:

Fehler-Kategorie

Relativ einfaches Debugging

Fehler bei der Kompilierung

Ganz einfach: Gehen Sie zur Linie und beheben Sie das Problem.

Laufzeit-Ausnahme

Mittel; die Kontrolle muss zum Fehler fließen, und er kann auf unvorhergesehene Randfälle oder schwer zu reproduzierende Zustände wie eine Wettlaufbedingung zwischen Threads zurückzuführen sein, aber zumindest erhalten wir eine klare Fehlermeldung und einen Stack-Trace, wenn er auftritt.

Stiller logischer Fehler

Schwierig; wir wissen vielleicht nicht einmal, dass es ihn gibt, und wenn wir ihn doch finden, kann es sehr schwierig sein, den verursachenden Staat ausfindig zu machen, da er nicht lokalisierbar ist und möglicherweise mehrere Behauptungen verletzt.

Wenn die Entwickler von Programmiersprachen über Programmsicherheit sprechen, besteht ein Hauptziel darin, echte Fehler aufzudecken und nicht zu unterdrücken, indem Laufzeitfehler zu Kompilierzeitfehlern und stille logische Fehler entweder zu Laufzeitausnahmen oder (idealerweise) zu Kompilierzeitfehlern gemacht werden.

Python ist als interpretierte Sprache so konzipiert, dass es in hohem Maße auf Laufzeitausnahmen statt auf Compilerfehler angewiesen ist. Fehlende Methoden oder Eigenschaften, illegale Typoperationen wie 1 + "a" und unzulässige oder fehlende Indizes oder Schlüssel werden standardmäßig ausgelöst.

Einige Sprachen wie JS, Java, Rust und Go verwenden standardmäßig das Fallback-Verhalten für ihre Maps (und bieten in vielen Fällen keine throw/raise-Alternative), aber Python wirft standardmäßig, zusammen mit anderen Sprachen wie C#. Perl/PHP geben eine Warnung bei nicht initialisierten Werten aus.

Willkürliche Anwendung von .get für alle Diktatzugriffe, auch für solche, bei denen ein Fehlschlag nicht zu erwarten ist und die keine Ausweichmöglichkeit für den Umgang mit None (oder welche Voreinstellung auch immer verwendet wird), die im Code Amok läuft, wirft so ziemlich Pythons Laufzeit-Ausnahme-Sicherheitsnetz für diese Klasse von Fehlern über den Haufen, indem es potenzielle Fehler zum Schweigen bringt oder ihnen eine Umleitung hinzufügt.

Weitere Gründe für die Bevorzugung von Klammersuchen (mit gelegentlichen, gut platzierten .get wo ein Standardwert erwartet wird):

  • Sie bevorzugen das Schreiben von standardmäßigem, idiomatischem Code unter Verwendung der von der Sprache bereitgestellten Werkzeuge. Python-Programmierer bevorzugen in der Regel (richtigerweise) Klammern aus den oben genannten Gründen der Ausnahmesicherheit und weil es das Standardverhalten für Python-Dicts ist.
  • Immer mit .get die Absicht verwirkt, wenn Sie Fälle schaffen, in denen Sie eine Voreinstellung erwarten None Wert, der nicht von einem Lookup zu unterscheiden ist, von dem Sie behaupten, dass er erfolgreich sein muss.
  • Die Komplexität der Tests nimmt proportional zu den neuen "legalen" Programmpfaden zu, die durch .get . Beide Fälle müssen getestet werden, um die Abdeckung zu gewährleisten, selbst wenn der Standardpfad durch die Spezifikation effektiv unerreichbar ist (was ironischerweise zu zusätzlichen if val is not None: o try für alle zukünftigen Verwendungen des abgerufenen Wertes; unnötig und verwirrend für etwas, das nie sein sollte None in erster Linie).
  • .get ist ein bisschen langsamer .
  • .get ist schwieriger zu tippen und hässlicher zu lesen (vergleiche Javas angeheftetes Gefühl ArrayList Syntax zu nativem C# Lists oder C++-Vektorcode). Unwichtig.

Einige Sprachen wie C++ und Ruby bieten alternative Methoden ( at y fetch ), um bei einem fehlerhaften Zugriff einen Fehler auszulösen, während C# einen Opt-in-Fallback-Wert bietet TryGetValue ähnlich wie bei Python get .

Seit JS, Java, Ruby, Go und Rust backen den Fallback-Ansatz von .get standardmäßig in alle Hash-Abfragen einbezieht, kann das doch nicht so schlimm sein, könnte man meinen. Es ist wahr, dass dies nicht das größte Problem ist, mit dem sich Sprachentwickler konfrontiert sehen, und es gibt viele Anwendungsfälle für die Version ohne Zugriffsmöglichkeit, daher ist es nicht überraschend, dass es keinen Konsens zwischen den Sprachen gibt.

Aber wie ich argumentiert habe, hat Python (zusammen mit C#) es besser gemacht als diese Sprachen, indem es die assert-Option zum Standard gemacht hat. Es ist ein Verlust an Sicherheit und Ausdruckskraft, wenn man die Option nicht verwendet, um Vertragsverletzungen am Punkt des Scheiterns zu melden, indem man wahllos .get in allen Bereichen.

5voto

AbstProcDo Punkte 17041

Warum dict.get(Schlüssel) anstelle von dict[Schlüssel]?

0. Zusammenfassung

Im Vergleich zu dict[key] , dict.get bietet einen Ausweichwert für die Suche nach einem Schlüssel.

1. Definition

get(Schlüssel[, Standard]) 4. Eingebaute Typen - Python 3.6.4rc1 Dokumentation

Rückgabe des Wertes für key, wenn key im Wörterbuch enthalten ist, sonst Standard. Wenn default nicht angegeben wird, ist es standardmäßig None, so dass diese Methode nie einen KeyError auslöst.

d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'

2. Problem, das es löst.

Wenn ohne default value müssen Sie umständliche Codes schreiben, um eine solche Ausnahme zu behandeln.

def get_harry_info(key):
    try:
        return "{}".format(d[key])
    except KeyError:
        return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'

Als bequeme Lösung, dict.get führt einen fakultativen Standardwert ein, der die oben genannten unwichtigen Codes vermeidet.

3. Schlussfolgerung

dict.get hat eine zusätzliche Option für den Standardwert, um die Ausnahme zu behandeln, wenn der Schlüssel nicht im Wörterbuch enthalten ist

5voto

אנונימי Punkte 154

Ein Unterschied, der ein Vorteil sein kann, besteht darin, dass wir, wenn wir nach einem Schlüssel suchen, der nicht existiert, None erhalten, nicht wie bei der Verwendung der Klammerschreibweise, bei der wir einen Fehler erhalten:

print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'

Das letzte, was an der get-Methode cool ist, ist, dass sie ein zusätzliches optionales Argument für einen Standardwert erhält, d.h. wenn wir versuchen, den Punktwert eines Schülers zu erhalten, aber der Schüler keinen Punktwertschlüssel hat, können wir stattdessen eine 0 erhalten.

Anstatt dies (oder etwas Ähnliches) zu tun:

score = None
try:
    score = dictionary["score"]
except KeyError:
    score = 0

Wir können dies tun:

score = dictionary.get("score", 0)
# score = 0

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X