2014-11-17 13 views
6

Molti SO post Visualizza come controllare in modo efficace l'esistenza di una chiave in un dizionario, per esempio, Check if a given key already exists in a dictionarycontrollo python multi-livello dict esistenza chiave

Come faccio a fare questo per una chiave a più livelli? Ad esempio, se d["a"]["b"] è un dict, come posso controllare se d["a"]["b"]["c"]["d"] esiste senza fare qualcosa di orrendo come questo:

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

C'è una sintassi simile

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

Quello che sto effettivamente usando questo per: abbiamo jsons, analizzati in dicts usando simplejson, di cui ho bisogno per estrarre i valori da. Alcuni di questi valori sono nidificati a tre e quattro livelli; ma a volte il valore non esiste affatto. Così ho voluto qualcosa di simile:

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

EDIT: Preferisco non crash se qualche sottochiave esiste ma non è un dizionario, per esempio, d["a"]["b"] = 5.

+0

Questa non è una caratteristica di base della lingua in quanto non v'è alcun modo per aggiungere nuovi sintassi. È possibile definire una nuova classe che sovrascrive la funzione __contains__ che viene chiamata dall'espressione "x in y". Vuoi l'efficienza della sintassi o dell'esecuzione? Potrebbero non essere la stessa cosa – mobiusklein

+0

Bene, il mio obiettivo era una sintassi efficiente, ma questo era nel presupposto che il tempo di ricerca del dizionario O (1) sarebbe stato preservato. Tuttavia, mi rendo conto che elevare le eccezioni è costoso, quindi forse questo è più complicato del semplice controllo dell'esistenza delle chiavi. – Tommy

+0

La gestione delle eccezioni non sarà la parte costosa. Quello che vuoi fondamentalmente non è nella lingua come sottolineato da utdemir. La risposta di Meitham è vicina a quella che vuoi ottenere senza fare molto più lavoro, definire una classe come ho detto prima, e poi passare attraverso la difficoltà di rendere 'simplejson' decomprimere oggetti in quel e non dizionari di vaniglia. – mobiusklein

risposta

7

Purtroppo non esiste alcuna sintassi incorporata o una libreria comune per interrogare dizionari del genere.

Tuttavia, credo che il più semplice (e penso che sia abbastanza efficiente) cosa che puoi fare è:

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

Edit: Non è molto comune, ma c'è: https://github.com/akesterson/dpath-python

Edit 2: Esempi:

>>> 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? E questo restituisce un booleano o l'oggetto? – Tommy

+0

Da 'help ({}. Get)': 'D.get (k [, d]) -> D [k] se k in D, altrimenti d. d il valore predefinito è Nessuno. Restituisce l'oggetto se viene trovato, "Nessuno" se non lo è. – utdemir

+0

Destra, errore di battitura, modificato. – utdemir

1

questo non è probabilmente una buona idea e non mi consiglia di utilizzare questo prod. Tuttavia, se lo fai solo per scopi di apprendimento, il sotto potrebbe funzionare per te.

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)