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.
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
.
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.
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]
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