Überprüfen Sie, ob ein bestimmter Schlüssel bereits in einem Wörterbuch vorhanden ist

2683

Ich wollte testen, ob ein Schlüssel in einem Wörterbuch vorhanden ist, bevor ich den Wert für den Schlüssel aktualisiere. Ich habe folgenden Code geschrieben:

if 'key1' in dict.keys():
  print "blah"
else:
  print "boo"

Ich denke, dies ist nicht der beste Weg, um diese Aufgabe zu erfüllen. Gibt es eine bessere Möglichkeit, einen Schlüssel im Wörterbuch zu testen?

Mohan Gulati
quelle
31
Beim Aufrufen dict.keys()wird eine Liste mit Schlüsseln gemäß der Dokumentation docs.python.org/2/library/stdtypes.html#dict.keys erstellt. Ich wäre jedoch überrascht, wenn dieses Muster in einer ernsthaften Implementierung nicht für die Übersetzung optimiert wäre zu if 'key1' in dict:.
Evgeni Sergeev
7
So fand ich schließlich heraus , warum viele meiner Python - Skripte so langsam waren :) :(. Das ist , weil ich habe mit x in dict.keys()für Schlüssel zu überprüfen. Und das geschah , weil die übliche Art und Weise zu iterieren Schlüssel in Java for (Type k : dict.keySet()), so dass diese Gewohnheit for k in dict.keys()zu fühlen sich natürlicher an als for k in dict(was sollte in Bezug auf die Leistung noch in Ordnung sein?), aber dann wird das Überprüfen der Schlüssel if k in dict.keys()auch, was ein Problem ist ...
Evgeni Sergeev
4
@EvgeniSergeev if k in dict_:testet das Vorhandensein von k in den KEYS von dict_, sodass Sie es immer noch nicht benötigen dict_.keys(). (Dies hat mich gebissen, wie es mir vorliest, als würde es auf einen Wert in dikt testen . Aber es ist nicht so.)
ToolmakerSteve
1
@ToolmakerSteve Das stimmt, aber Sie brauchen es nicht nur nicht, es ist auch keine gute Praxis.
Evgeni Sergeev
26
Versuchen Sie "key in dict"
marcelosalloum

Antworten:

3371

inist die beabsichtigte Methode, um die Existenz eines Schlüssels in a zu testen dict.

d = {"key1": 10, "key2": 23}

if "key1" in d:
    print("this will execute")

if "nonexistent key" in d:
    print("this will not")

Wenn Sie eine Standardeinstellung wünschen, können Sie immer Folgendes verwenden dict.get():

d = dict()

for i in range(100):
    key = i % 10
    d[key] = d.get(key, 0) + 1

und wenn Sie immer einen Standardwert für einen Schlüssel sicherstellen möchten, können Sie diesen entweder dict.setdefault()wiederholt oder defaultdictüber das collectionsModul verwenden, wie folgt:

from collections import defaultdict

d = defaultdict(int)

for i in range(100):
    d[i % 10] += 1

Im Allgemeinen ist das inSchlüsselwort jedoch der beste Weg, dies zu tun.

Chris B.
quelle
74
Ich benutze es normalerweise nur, getwenn ich den Gegenstand trotzdem aus dem Wörterbuch ziehen will. Es macht keinen Sinn bei der Verwendung in und das Element aus dem Wörterbuch zu ziehen.
Jason Baker
75
Ich stimme vollkommen zu. Wenn Sie jedoch nur wissen müssen, ob ein Schlüssel vorhanden ist, oder zwischen einem Fall, in dem der Schlüssel definiert ist, und einem Fall, in dem Sie einen Standard verwenden, unterscheiden müssen, inist dies der beste Weg.
Chris B.
5
Referenz für diese Antwort ist in den Python-Dokumenten
Enkash
30
get ist ein schlechter Test, wenn der Schlüssel beispielsweise "False" entspricht 0. Das habe ich auf die harte
Sebastien
4
Ich kann nicht zustimmen, dass dies eine vollständige Antwort ist, da nicht erwähnt wird, dass "try" - "außer" am schnellsten ist, wenn die Anzahl der fehlgeschlagenen Schlüssel ausreichend klein ist. Siehe diese Antwort unten: stackoverflow.com/a/1602945/4376643
Craig Hicks
1546

Sie müssen keine Tasten anrufen:

if 'key1' in dict:
  print("blah")
else:
  print("boo")

Dies ist viel schneller, da das Hashing des Wörterbuchs verwendet wird, anstatt eine lineare Suche durchzuführen, wie dies beim Aufrufen von Schlüsseln der Fall wäre.

Jason Baker
quelle
7
Das ist großartig. Ich hatte den Eindruck, dass es intern immer noch die Liste der Schlüssel durchlaufen würde, aber ich sehe, dass dies eher wie das Testen der Mitgliedschaft in einem Satz funktioniert.
Mohan Gulati
51
@ Mohan Gulati: Sie verstehen, dass ein Wörterbuch eine Hashtabelle von Schlüsseln ist, die Werten zugeordnet sind, oder? Ein Hashing-Algorithmus konvertiert den Schlüssel in eine Ganzzahl und die Ganzzahl wird verwendet, um eine übereinstimmende Position in der Hash-Tabelle zu finden. en.wikipedia.org/wiki/Hash_table
hughdbrown
5
@Charles Addis, aus Erfahrung mit rund einer halben Million Schlüsseln erhalten Sie mindestens 10-fache Leistungssteigerung, wenn Sie "key in dict" anstelle von "key in dict.keys ()" schreiben. PEP und Zen geben außerdem an, dass Sie sie ignorieren sollten, falls sie für Ihr Projekt schlecht sind.
ivan_bilan
11
ivan_bilan - Ich habe gerade meinen eigenen Test durchgeführt ... Bei einer halben Million Schlüsseln if key in d1dauerte es 0.17265701293945312Sekunden. Berufung if key in d1.keys()hat 0.23871088027954102- das ist die klassische Definition einer Mikro-Optimierung. 0.07884883880615234Sekunden sparen ist keine Leistungssteigerung.
Charles Addis
11
@Eli Nur für dich habe ich einen Test erstellt, den du selbst ausführen kannst. Die Ergebnisse können Sie in Erstaunen versetzen. Bei Diktaten mit ~ 50.000 Schlüsseln keys()bietet das Nichtanrufen einen Rechenvorteil von 0,01 Sekunden. Bei ~ 500.000 Schlüsseln erhalten keys()Sie einen Vorteil von 0,1 Sekunden, wenn Sie nicht anrufen . Für ~ 5.000.000 Schlüssel, nicht Aufruf keys()ist 0,4 Sekunden schneller, aber für 50.000.000 Schlüssel CALLING keys()IS 3 Sekunden schneller!
Charles Addis
268

Sie können in einem Wörterbuch für das Vorhandensein eines Schlüssels testen, die mit in Stichworten:

d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False

Eine häufige Verwendung zum Überprüfen der Existenz eines Schlüssels in einem Wörterbuch vor dem Mutieren besteht darin, den Wert standardmäßig zu initialisieren (z. B. wenn Ihre Werte beispielsweise Listen sind und Sie sicherstellen möchten, dass eine leere Liste vorhanden ist, an die Sie anhängen können beim Einfügen des ersten Wertes für einen Schlüssel). In solchen Fällen ist der collections.defaultdict()Typ möglicherweise von Interesse.

In älterem Code finden Sie möglicherweise auch einige Verwendungen has_key()einer veralteten Methode zum Überprüfen der Existenz von Schlüsseln in Wörterbüchern (verwenden Sie key_name in dict_namestattdessen einfach ).

Michael Aaron Safyan
quelle
2
Wollte mitteilen, dass (mit Python 2.7) die Laufzeit von etwas, das ich gerade geschrieben habe und das stark auf Diktaten basiert, 363.235070 mit "key in dict.keys ()" betrug und drastisch auf 0.260186 sank, nur indem der Aufruf für "Schlüssel entfernt wurde ( ) "
Ido_f
@Ido_f bitte posten Sie Ihre Benchmarks, da meine Benchmarks fast keinen Unterschied in 3.5 und 2.7
Charles Addis
@Ido_f Ich vermute, es war etwas anderes in Ihrem Programm, das etwas anderes war, aber eigentlich nicht key in dict.keys(). Versuchen Sie, den gesamten Code mit Ausnahme dieser Überprüfung zu entfernen, und sehen Sie, was Ihr Ergebnis ist.
Charles Addis
101

Sie können dies verkürzen:

if 'key1' in dict:
    ...

Dies ist jedoch bestenfalls eine kosmetische Verbesserung. Warum glaubst du, ist das nicht der beste Weg?

Greg Hewgill
quelle
100
Dies ist viel mehr als eine kosmetische Verbesserung. Die Zeit, um einen Schlüssel mit dieser Methode zu finden, ist O (1), während das Aufrufen von Schlüsseln eine Liste erzeugen und O (n) sein würde.
Jason Baker
5
Das O (1) scheint nicht ganz richtig zu sein. Bist du sicher, dass es nicht so etwas wie O (log n) ist?
Spektren
12
Es ist die Komplexität einer einzelnen Diktatsuche, die im Durchschnitt O (1) und im schlimmsten Fall O (n) beträgt. .list () ist immer O (n). wiki.python.org/moin/TimeComplexity
Leonora Tindall
1
Dies vermeidet auch eine zusätzliche Zuordnung. (wichtig, um enge Schleifen etwas schneller zu machen)
Nurettin
56

Weitere Informationen zur Geschwindigkeitsausführung der vorgeschlagenen Methoden der akzeptierten Antwort (10-m-Schleifen):

  • 'key' in mydict verstrichene Zeit 1,07 Sek
  • mydict.get('key') verstrichene Zeit 1,84 Sek
  • mydefaultdict['key'] verstrichene Zeit 1,07 Sek

Verwenden Sie daher inoder defaultdictwerden dagegen empfohlen get.

Wtower
quelle
6
stimme getvoll und ganz zu, dass 's 1.84s <1.07 * 2 ;-P
Paul Rigor
54

Ich würde empfehlen, stattdessen die setdefaultMethode zu verwenden. Es klingt so, als würde es alles tun, was Sie wollen.

>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}
David Berger
quelle
9
Was hat setdefaultmit der Frage des OP zu tun?
Hughdbrown
18
@hughdbrown "Ich wollte testen, ob ein Schlüssel in einem Wörterbuch vorhanden ist, bevor ich den Wert für den Schlüssel aktualisiere." Manchmal enthalten Posts Code, der eine Flut von Antworten auf etwas erzeugt, das nicht ganz das ursprüngliche Ziel ist. Um das im ersten Satz angegebene Ziel zu erreichen, ist setdefault die effektivste Methode, auch wenn es kein Ersatz für den veröffentlichten Beispielcode ist.
David Berger
5
Dies ist die überlegene Antwort, da sie das Ziel von OP erfüllt, anstatt nur die technisch korrekte Antwort zu geben. Siehe: nedbatchelder.com/blog/201207/…
Niels Bom
+1 für eine informative Antwort, die mir etwas beigebracht hat. Ob dies die beste Lösung ist, hängt jedoch davon ab, was der Codierer im Sinn hat. zB die Bedeutung von "vor dem Aktualisieren des Wertes des Schlüssels". Vielleicht wird er eine Ausnahme auslösen, wenn sie nicht vorhanden ist (== keine Berechtigung zum Hinzufügen neuer Schlüssel). Vielleicht ist es ein Wörterbuch der Zählungen, und er wird 1 zur vorhandenen Zählung hinzufügen. In diesem Fall ist "d [Schlüssel] = d.get (Schlüssel, 0) + 1" die sauberste Lösung (wie Chris nach Ihrer Antwort zeigt wurde geschrieben). (Ich erwähne dies nur, falls zukünftige Leser mit unterschiedlichen Aufgaben hierher kommen.)
ToolmakerSteve
1
@ToolmakerSteve True. Das Problem hierbei ist, dass die Frage von OP nicht klar genug war.
Niels Bom
45

Das Wörterbuch in Python verfügt über eine get-Methode ('key', Standard). Sie können also einfach einen Standardwert festlegen, falls kein Schlüssel vorhanden ist.

values = {...}
myValue = values.get('Key', None)
Mafonya
quelle
33

Was ist mit der Verwendung von EAFP (leichter um Vergebung als um Erlaubnis zu bitten):

try:
   blah = dict["mykey"]
   # key exists in dict
except KeyError:
   # key doesn't exist in dict

Siehe andere SO-Beiträge:

Verwenden Sie try vs if in Python oder

Überprüfen der Existenz von Mitgliedern in Python

HungryArthur
quelle
12
Try / Except kann teurer sein, wenn es wahrscheinlich ist, dass der Schlüssel häufig nicht vorhanden ist. Aus dem Beitrag, auf den Sie verwiesen haben: "[I] Wenn Sie erwarten, dass 99% des Zeitergebnisses tatsächlich etwas Iterierbares enthalten, würde ich den try / exception-Ansatz verwenden. Es ist schneller, wenn Ausnahmen wirklich außergewöhnlich sind. Wenn das Ergebnis None ist In mehr als 50% der Fälle ist die Verwendung von if wahrscheinlich besser. [...] [A] n Wenn die Anweisung Sie immer kostet, ist es fast kostenlos, einen try / exception-Block einzurichten. Wenn jedoch tatsächlich eine Ausnahme auftritt, wird die Kosten sind viel höher. " stackoverflow.com/a/1835844/1094092
billrichards
28

Verwenden des ternären Operators:

message = "blah" if 'key1' in dict else "booh"
print(message)
Charitoo
quelle
20

Die Möglichkeiten, wie Sie die Ergebnisse erhalten können, sind:

  • if your_dict.has_key (Schlüssel) In Python 3 entfernt
  • Wenn Sie your_dict eingeben
  • versuchen / außer blockieren

Was besser ist, hängt von drei Dingen ab:

  1. Hat das Wörterbuch "normalerweise den Schlüssel" oder "hat normalerweise nicht den Schlüssel".
  2. Beabsichtigen Sie Bedingungen wie if ... else ... elseif ... else zu verwenden?
  3. Wie groß ist das Wörterbuch?

Lesen Sie mehr: http://paltman.com/try-except-performance-in-python-a-simple-test/

Verwendung von try / block anstelle von 'in' oder 'if':

try:
    my_dict_of_items[key_i_want_to_check]
except KeyError:
    # Do the operation you wanted to do for "key not present in dict".
else:
    # Do the operation you wanted to do with "key present in dict."
Bishwas Mishra
quelle
2
Gut, muss aber für Python 3 aktualisiert werden. Ich habe das Skript der Webseite mit konvertiert 2to3und festgestellt, dass die Syntax ohne Versuch immer schneller ist als die Syntax mit Versuch, selbst wenn sich der Schlüssel im Diktat befindet.
Jean Paul
18

Nur Python 2: (und Python 2.7 unterstützt inbereits)

Sie können die Methode has_key () verwenden:

if dict.has_key('xyz')==1:
    #update the value for the key
else:
    pass
Wan Kenobi
quelle
22
.has_key()wurde veraltet ; Sie sollten inwie in anderen Antworten gezeigt verwenden.
Brad Koch
12
Übrigens empfehle ich, ALLE vorhandenen Antworten auf eine ALTE Frage zu lesen , bevor Sie sie beantworten. Diese Antwort fügte nichts hinzu, da der Vorschlag bereits in Michaels Antwort von '09 existierte. (Ich möchte nicht davon abhalten, einer Diskussion etwas Nützliches hinzuzufügen. Versuchen Sie es weiter.)
ToolmakerSteve
16

Nur eine Info zu Chris. B (beste Antwort):

d = defaultdict(int)

Funktioniert auch; Der Grund dafür ist, dass der Aufruf int()zurückgibt 0, was defaultdicthinter den Kulissen (beim Erstellen eines Wörterbuchs) geschieht, daher der Name "Factory Function" in der Dokumentation.

Mauricio Morales
quelle
2
Wenn Sie ein Wörterbuch mit Zählungen erstellen, sollten Sie Counter verwenden (unter der Annahme von Python 2.7). Und ich habe verwendetdefaultdict(lambda: 0) statt verwendet, defaultdict(int)weil ich denke, es ist klarer, was los ist; Der Leser muss nicht wissen, dass Sie erhalten, 0wenn Sie int()ohne Argumente anrufen . YMMV.
Chris B.
9

Überprüfen Sie, ob ein bestimmter Schlüssel bereits in einem Wörterbuch vorhanden ist

Um die Idee zu bekommen, wie das geht, überprüfen wir zuerst, welche Methoden wir im Wörterbuch aufrufen können. Hier sind die Methoden:

d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}

Python Dictionary clear()       Removes all Items
Python Dictionary copy()        Returns Shallow Copy of a Dictionary
Python Dictionary fromkeys()    Creates dictionary from given sequence
Python Dictionary get()         Returns Value of The Key
Python Dictionary items()       Returns view of dictionary (key, value) pair
Python Dictionary keys()        Returns View Object of All Keys
Python Dictionary pop()         Removes and returns element having given key
Python Dictionary popitem()     Returns & Removes Element From Dictionary
Python Dictionary setdefault()  Inserts Key With a Value if Key is not Present
Python Dictionary update()      Updates the Dictionary 
Python Dictionary values()      Returns view of all values in dictionary

Die brutale Methode, um zu überprüfen, ob der Schlüssel bereits vorhanden ist, kann die folgende sein get():

d.get("key")

Die anderen beiden interessanten Methoden items()und keys()klingt nach zu viel Arbeit. Lassen Sie uns also untersuchen, ob dies get()die richtige Methode für uns ist. Wir haben unser Diktat d:

d= {'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}

Der Druck zeigt, dass der Schlüssel, den wir nicht haben, zurückgegeben wird None:

print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1

Wir können das verwenden, um die Informationen zu erhalten, ob der Schlüssel vorhanden ist oder nicht. Aber bedenken Sie dies, wenn wir ein Diktat mit einem einzigen erstellen key:None:

d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None

Das Führen dieser get()Methode ist nicht zuverlässig, falls einige Werte vorliegen None. Diese Geschichte sollte ein glücklicheres Ende haben. Wenn wir den inKomparator verwenden:

print('key' in d) #True
print('key2' in d) #False

Wir bekommen die richtigen Ergebnisse. Wir können den Python-Bytecode untersuchen:

import dis
dis.dis("'key' in d")
#   1           0 LOAD_CONST               0 ('key')
#               2 LOAD_NAME                0 (d)
#               4 COMPARE_OP               6 (in)
#               6 RETURN_VALUE

dis.dis("d.get('key2')")
#   1           0 LOAD_NAME                0 (d)
#               2 LOAD_METHOD              1 (get)
#               4 LOAD_CONST               0 ('key2')
#               6 CALL_METHOD              1
#               8 RETURN_VALUE

Dies zeigt, dass in Vergleichsoperator nicht nur zuverlässiger, sondern sogar schneller ist als get().

Prosti
quelle
.get()kann ein zweites Argument für den defaultWert haben, das verwendet werden kann, um das Problem zu behandeln, wo key:None. Beispiel: d.get("key", False)
Alex
.get()ist der schnellste Weg. Eine andere Option ist die Zuweisung in einem try/ exceptBlock
HCLivess
7

Python-Wörterbuch hat die Methode aufgerufen __contains__. Diese Methode gibt True zurück, wenn das Wörterbuch den Schlüssel hat. Andernfalls wird False zurückgegeben.

 >>> temp = {}

 >>> help(temp.__contains__)

Help on built-in function __contains__:

__contains__(key, /) method of builtins.dict instance
    True if D has a key k, else False.
Siva Gnanam
quelle
2
Es ist sehr schlecht, __contains__direkt anzurufen . Die richtige Vorgehensweise besteht darin, den inOperator zu verwenden , der containment checkdie __contains__Funktion aufruft .
user1767754
@ user1767754 Ich benutze foo = x['foo'] if x.__contains__('foo') else 'bar'. Irgendwelche Ideen, wie der inOperator als Teil dieses Ausdrucks verwendet werden könnte?
Donrondadon
1
foo = x['foo'] if 'foo' in x else 'bar'
Ray Wu
5

Teilen Sie eine weitere Möglichkeit, mit booleschen Operatoren zu überprüfen, ob ein Schlüssel vorhanden ist.

d = {'a': 1, 'b':2}
keys = 'abcd'

for k in keys:
    x = (k in d and 'blah') or 'boo'
    print(x) 

Dies kehrt zurück

>>> blah
>>> blah
>>> boo
>>> boo

Erläuterung

Zunächst sollten Sie wissen , dass in Python, 0, Noneoder Objekte mit der Länge Null bewerten zu False. Alles andere wird ausgewertet True. Boolesche Operationen werden von links nach rechts ausgewertet und geben den Operanden nicht True oder False zurück.

Sehen wir uns ein Beispiel an:

>>> 'Some string' or 1/0 
'Some string'
>>>

Da 'Some string'ausgewertet wird, Truewird der Rest von ornicht ausgewertet und es wird keine Division durch Nullfehler ausgelöst.

Wenn wir jedoch wechseln, wird die Reihenfolge 1/0zuerst ausgewertet und eine Ausnahme ausgelöst:

>>> 1/0 or 'Some string'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 

Wir können dieses Muster verwenden, um zu überprüfen, ob ein Schlüssel vorhanden ist.

(k in d and 'blah')

macht das gleiche wie

if k in d:
    'blah'
else:
    False

Dies gibt bereits das richtige Ergebnis zurück, wenn der Schlüssel vorhanden ist, aber wir möchten, dass er 'boo' druckt, wenn dies nicht der Fall ist. Also nehmen wir das Ergebnis und ores mit'boo'

>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>> 
J. Antunes
quelle
1

Sie können die forSchleife verwenden, um das Wörterbuch zu durchlaufen und den Namen des Schlüssels abzurufen, den Sie im Wörterbuch finden möchten. Überprüfen Sie anschließend, ob er vorhanden ist oder nicht: Verwenden Sie die ifBedingung:

dic = {'first' : 12, 'second' : 123}
for each in dic:
    if each == 'second': 
        print('the key exists and the corresponding value can be updated in the dictionary')
Abdulkalek
quelle
Überprüfen Sie den Code, da die Ausgabe dafür it is existundnot exist
system123456
Warum überhaupt ein Wörterbuch verwenden, um eine lineare Suche durchzuführen?
Jean-François Fabre