Chained, nested dict() get calls in python
How about using a small helper function?
def getn(d, path):
for p in path:
if p not in d:
return None
d = d[p]
return d
and then
[getn(m, ["gparents", "parent", "child"]) for m in M]
Since these are all python dict
s and you are calling the dict.get()
method on them, you can use an empty dict
to chain:
[m.get("gparents", {}).get("parent", {}).get("child") for m in M]
By leaving off the default for the last .get()
you fall back to None
. Now, if any of the intermediary keys is not found, the rest of the chain will use empty dictionaries to look things up, terminating in .get('child')
returning None
.
Another approach is to recognize that if the key isn't found, dict.get
returns None
. However, None
doesn't have an attribute .get
, so it will throw an 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???
Just like Martijn's answer, this doesn't guarantee that X
is iterable (non-None
). Although, you could fix that by making the last get
in the chain default to returning an empty list:
try:
X = m.get("gparents").get("parent").get("child",[])
except AttributeError:
continue
Finally, I think that probably the best solution to this problem is to use reduce
:
try:
X = reduce(dict.__getitem__,["gparents","parent","child"],m)
except (KeyError,TypeError):
pass
else:
for x in X:
#do something with x
The advantage here is that you know if any of the get
s failed based on the type of exception that was raised. It's possible that a get
returns the wrong type, then you get a TypeError
. If the dictionary doesn't have the key however, it raises a KeyError
. You can handle those separately or together. Whatever works best for your use case.