Zuerst wird key in d.keys()
Ihnen garantiert den gleichen Wert wie key in d
für jedes dict d
geben.
Und der in
Betrieb auf einem dict
oder dict_keys
Objekt, das Sie von Aufrufen keys()
auf sie zurück (in 3.x) ist nicht O (N), ist es O (1).
Es gibt keine wirkliche "Optimierung"; Es ist nur so, dass die Verwendung des Hashs die naheliegende Methode ist, in einer Hash-Tabelle zu implementieren, genauso wie es der offensichtliche Weg ist, __getitem__
zu implementieren.
Sie können fragen, wo das garantiert ist.
Nun, ist es nicht. Mapping Types definiert dict
als im Grunde eine Hash-Tabelle Implementierung von collections.abc.Mapping
. Es gibt nichts, was jemanden davon abhält, eine Hashtabellenimplementierung eines Mappings zu erstellen, aber dennoch O (N) -Suchen durchzuführen. Aber es wäre zusätzliche Arbeit, um solch eine schlechte Implementierung zu machen, also warum sollten sie?
Wenn Sie wirklich es sich selbst beweisen müssen, Sie jede Implementierung kümmern uns um Sie testen (mit einem Profiler oder durch irgendeine Art mit einem benutzerdefinierten __hash__
und __eq__
verwenden, Anrufe oder ... anmeldet), oder lesen Sie die Quelle .
In 2.x, mögen Sie nicht keys
nennen, denn das ist ein list
des Schlüssels erzeugt, anstelle ein KeysView
. Sie könnten iterkeys
verwenden, aber das könnte einen Iterator oder etwas anderes erzeugen, das nicht O (1) ist. Verwenden Sie also das Diktat selbst als Sequenz.
Auch in 3.x möchten Sie nicht keys
anrufen, weil es nicht nötig ist. Iterating ein dict
, überprüft seine , und im Allgemeinen zu behandeln, wie eine Sequenz ist immer gleichbedeutend mit der gleichen Sache zu seinen Schlüsseln, also warum stören?(Und natürlich bauen die trivialen KeyView
, und den Zugriff darauf, fügen Sie ein paar Nanosekunden zu Ihrer Laufzeit und ein paar Tastenanschläge für Ihr Programm.)
(Es ist nicht ganz klar, dass die Verwendung von Sequenz-Operationen für/und d
in 2.x. Abgesehen von Leistungsproblemen sind sie sind gleichbedeutend in jeder CPython, Jython, IronPython und PyPy-Implementierung, aber es scheint nicht irgendwo angegeben, wie es in 3.x ist . Und es spielt keine Rolle, nur key in d
verwenden)
Während wir sind. Beachten Sie, dass dies:
if(dict[key] != None):
... wird nicht funktionieren. Wenn die key
nicht in der dict
ist, erhöht dies KeyError
, nicht zurück None
.
Sie sollten auch nie None
mit ==
oder !=
überprüfen; Verwenden Sie immer is
.
Sie können dies mit einem try
-oder einfacher tun tun if dict.get(key, None) is not None
tun. Aber auch dafür gibt es keinen Grund. Das wird auch keine Fälle behandeln, in denen None
ein vollkommen gültiger Gegenstand ist. Wenn das der Fall ist, müssen Sie etwas wie sentinel = object(); if dict.get(key, sentinel) is not sentinel:
tun.
Also, das Richtige zu schreiben:
if key in d:
Allgemeiner dies nicht wahr ist:
I know the "in" keyword is generally O(n) (as this just translates to python iterating over an entire list and comparing each element
Der in
Betreiber, wie die meisten anderen Betreiber, ist nur ein Aufruf an eine -Methode (oder das Äquivalent für eine C/Java/.NET/RPython-Built-in). list
implementiert es durch Iterieren der Liste und Vergleichen jedes Elements; dict
implementiert es durch Hashing den Wert und Nachschlagen des Hash; blist.blist
implementiert es durch einen B + Baum zu Fuß; usw. Es könnte also O (n), O (1), O (log n) oder etwas völlig anderes sein.
Ich sage, was am einfachsten ist, und Profil später. – jh314
Eigentlich würde der Code unten nicht funktionieren. Sie müssen etwas tun, was "versuchen: dict [key]; außer KeyError: pass; sonst: # ... code ... '. –
@TravisGD Das ist ein guter Punkt, ich habe das vergessen – tknickman