Chained, nested dict () recevoir les appels en python

j'interroge un dictionnaire imbriqué en utilisant le dict.get('mot-clé') de la méthode. Actuellement, ma syntaxe est...

M = cursor_object_results_of_db_query

for m in M:
    X = m.get("gparents").get("parent").get("child")
    for x in X:
        y = x.get("key")

Cependant, parfois celui de "parent" ou "enfant" balises n'existe pas, et mon script échoue. Je sais à l'aide de get() je peux inclure un défaut dans le cas où la clé n'existe pas de forme...

get("parent", '') or
get("parent", 'orphan') 

Mais si je comprend tout Null,'', ou de vide, que je pense, les enchaînés .get("child") échoue lorsqu'il est appelé ''.get("child") depuis "" n'a pas de méthode .get().

La façon dont je suis la résolution de ça maintenant, c'est à l'aide d'un tas de séquentiel try-except autour de chaque .get("") appel, mais cela semble stupide et unpython---est-il un moyen de retour par défaut "skip" ou "pass" ou quelque chose qui soutiendrait toujours l'enchaînement et échouerait intelligemment, plutôt que de plonger profondément dans des clés qui n'existent pas?

Idéalement, je voudrais être une compréhension de liste de la forme:

[m.get("gparents").get("parent").get("child") for m in M]

mais c'est actuellement impossible quand un parent absent provoque le .get("child") appel pour mettre fin à mon programme.

18
demandé sur Martijn Pieters 2013-01-23 20:24:13

4 réponses

puisque ce sont tous des python dict s et vous appelez le dict.get() méthode, vous pouvez utiliser un vide dict à la chaîne:

[m.get("gparents", {}).get("parent", {}).get("child") for m in M]

En laissant la valeur par défaut pour la dernière .get() vous tomber en arrière None. Maintenant, si l'une des clés intermédiaires n'est pas trouvée, le reste de la chaîne va utiliser des dictionnaires vides pour rechercher des choses, se terminant par .get('child') retour None.

60
répondu Martijn Pieters 2013-01-23 16:32:26

une autre approche consiste à reconnaître que si la clé n'est pas trouvée, dict.get retourne None. Cependant, None n'a pas d'attribut .get, donc il lancera un AttributeError:

for m in M:
    try:
       X = m.get("gparents").get("parent").get("child")
    except AttributeError:
       continue

    for x in X:
        y = x.get("key")
        #do something with `y` probably???

tout comme la réponse de Martijn, cela ne garantit pas que X est itérable (non -None). Bien que, vous pourriez corriger cela en faisant le dernier get dans la chaîne par défaut de renvoyer une liste vide:

 try:
    X = m.get("gparents").get("parent").get("child",[])
 except AttributeError:
    continue

enfin, je pense que probablement le la meilleure solution à ce problème est d'utiliser reduce:

try:
    X = reduce(dict.__getitem__,["gparents","parent","child"],m)
except (KeyError,TypeError):
    pass
else:
    for x in X:
       #do something with x

L'avantage ici est que vous savez si l'un des get s échoué en fonction du type d'exception qui a été soulevée. Il est possible que a get renvoie le mauvais type, puis vous obtenez un TypeError. Si le dictionnaire n'a pas la clé cependant, il soulève un KeyError. Vous pouvez gérer séparément ou ensemble. Ce qui fonctionne le mieux pour votre cas d'utilisation.

7
répondu mgilson 2013-01-23 16:52:06

pourquoi ne pas utiliser une petite fonction d'assistance?

def getn(d, path):
    for p in path:
        if p not in d:
            return None
        d = d[p]
    return d

et

[getn(m, ["gparents", "parent", "child"]) for m in M]
4
répondu georg 2013-01-23 16:41:41

je me rends compte que je suis un peu en retard pour le rôle mais voici la solution que j'ai trouvée face à un problème similaire:

def get_nested(dict_, *keys, default=None):
    if not isinstance(dict_, dict):
        return default
    elem = dict_.get(keys[0], default)
    if len(keys) == 1:
        return elem
    return get_nested(elem, *keys[1:], default=default)

Par exemple:

In [29]: a = {'b': {'c': 1}}
In [30]: get_nested(a, 'b', 'c')
Out[30]: 1
In [31]: get_nested(a, 'b', 'd') is None
Out[31]: True
3
répondu Kevin Dungs 2017-10-17 12:25:20