2014-11-17 12 views
6

Viele SO Beiträge zeigen, wie effizient die Existenz eines Schlüssels in einem Wörterbuch zu überprüfen, zum Beispiel Check if a given key already exists in a dictionaryPython-Check Multi-Level-dict Schlüssel Existenz

Wie kann ich tun dies für eine Multi-Level-Schlüssel? wenn d["a"]["b"] ein dict Zum Beispiel ist, wie kann ich überprüfen, ob d["a"]["b"]["c"]["d"] ohne etwas horrend wie dies zu tun gibt:

if "a" in d and isInstance(d["a"], dict) and "b" in d["a"] and isInstance(d["a"]["b"], dict) and ... 

Gibt es eine Syntax wie

if "a"/"b"/"c"/"d" in d 

Was ich benutze das eigentlich für: wir haben jsons, die in dicts unter Verwendung von simplejson geparst sind, von denen ich Werte extrahieren muss. Einige dieser Werte sind drei oder vier Ebenen tief verschachtelt. aber manchmal existiert der Wert gar nicht. Also wollte ich so etwas wie:

val = None if not d["a"]["b"]["c"]["d"] else d["a"]["b"]["c"]["d"] #here d["a"]["b"] may not even exist 

EDIT: lieber nicht zum Absturz bringen, wenn einige Unterschlüssel vorhanden ist, aber kein Wörterbuch, z.B. d["a"]["b"] = 5.

+0

Dies ist kein Basis Merkmal der Sprache, da es keine Möglichkeit gibt, neue hinzufügen Syntax. Sie könnten eine neue Klasse definieren, die die Funktion __contains__ überschreibt, die vom Ausdruck "x in y" aufgerufen wird. Möchten Sie die Effizienz der Syntax oder Ausführung? Sie sind vielleicht nicht das Gleiche. – mobiusklein

+0

Nun, mein Ziel war effiziente Syntax, aber dies unter der Annahme, dass die O (1) Wörterbuch-Lookup-Zeit erhalten bleiben würde. Ich stelle jedoch fest, dass das Aufheben von Ausnahmen teuer ist, also ist dies vielleicht mehr als nur das Überprüfen der Schlüsselexistenz. – Tommy

+0

Ausnahmebehandlung wird nicht der kostspielige Teil sein. Was du grundsätzlich willst, ist nicht in der Sprache, wie du darauf hingewiesen hast. Meithams Antwort ist so nah, wie Sie zu dem kommen, was Sie wollen, ohne viel mehr Arbeit zu verrichten, eine Klasse wie bereits erwähnt zu definieren und dann das Problem zu lösen, dass 'simplejson' Objekte in diese und nicht in Vanilla-Wörterbücher entpackt. – mobiusklein

Antwort

7

Leider gibt es keine integrierte Syntax oder eine allgemeine Bibliothek, um solche Wörterbücher abzufragen.

Ich glaube jedoch, die einfachste (und ich denke, es ist effizient genug ist), was man tun kann, ist:

d.get("a", {}).get("b", {}).get("c") 

Edit: Es ist nicht sehr häufig, aber es gibt: https://github.com/akesterson/dpath-python

Edit 2: Beispiele:

>>> d = {"a": {"b": {}}} 
>>> d.get("a", {}).get("b", {}).get("c") 
>>> d = {"a": {}} 
>>> d.get("a", {}).get("b", {}).get("c") 
>>> d = {"a": {"b": {"c": 4}}} 
>>> d.get("a", {}).get("b", {}).get("c") 
4 
+0

d.get? Und gibt das einen booleschen oder den Gegenstand zurück? – Tommy

+0

Von 'help ({}. Get)': 'D.get (k [, d]) -> D [k] falls k in D, sonst d. d ist standardmäßig auf Keine eingestellt. Es gibt das Element zurück, wenn es gefunden wird, "None", wenn es nicht gefunden wird. – utdemir

+0

Rechts, Tippfehler, bearbeitet. – utdemir

1

Das ist nicht wahrscheinlich eine gute Idee, und ich würde mit diesem in prod nicht empfehlen. Wenn Sie es jedoch nur zu Lernzwecken tun, könnte das Folgende für Sie funktionieren.

def rget(dct, keys, default=None): 
    """ 
    >>> rget({'a': 1}, ['a']) 
    1 
    >>> rget({'a': {'b': 2}}, ['a', 'b']) 
    2 
    """ 
    key = keys.pop(0) 
    try: 
     elem = dct[key] 
    except KeyError: 
     return default 
    except TypeError: 
     # you gotta handle non dict types here 
     # beware of sequences when your keys are integers 
    if not keys: 
     return elem 
    return rget(elem, keys, default)