How to build a simple “deep_get” function for nested dictionaries in Python

Flávio Teixeira
2 min readApr 16, 2023

Accessing data from nested dictionaries in python can be kinda messy. Normally you can:

  • Use a bunch of if clauses;
  • Set a sequence of getmethods, returning an empty dictionary in each of the default values.
d = {
"obj_a": { "field_x": 1, "field_y": 2},
"obj_b": {
"obj_nested": {"field_z": 3}
}
}

# to get the value of field_z using if approach
field_z = None
if "obj_b" in d and \
"obj_nested" in d["obj_b"] and \
"field_z" in d["obj_b"]["obj_nested"]:
field_z = d["obj_b"]["obj_nested"].get("field_z")

# to get the value of field_z using sequence get methods
field_z = d.get("obj_b", dict()).get("obj_nested", dict()).get("field_z")

In both cases we end up with a code that is hard to read (imagine a script with a higher number of cases like this) and hard to maintain a well (debuging something like this is terrible).

While working with some very complex yaml configurations file, I came up with a simple solution that solve the problems above and works perfecly:

from functools import reduce

def deep_get(dictionary, keys, default=None, target_type=None):
value = reduce(
lambda d, key: d.get(key, default) if isinstance(d, dict) else default,
keys.split("."),
dictionary
)
return value if not target_type else target_type(value)

It receives 2 required parameters, the dictionary itself and a string representing the key and inner keys where the desired value is contained (separated by .).
It can also receive 2 optional parameters, a default value (just like the actual get function of the dictionary structure) to be returned and a type class for the value to be cast to.

Since I based it in the dictionaryget function, it also does not raise an Exception if any of the keys does not exist, it just returns the set default value (or None ).
Lets see its usage with the same dictionary as in the example above:

d = {
"obj_a": { "field_x": 1, "field_y": 2},
"obj_b": {
"obj_nested": {"field_z": 3}
}
}

field_z = deep_get(d, "obj_b.obj_nested.field_z")

See? A LOT cleaner. Solutions like this can help a lot to maintain the code in the near future and for new team members to understand the whole logic involved as well.

The snippet used in this example can also be found here.
Feel free to access my other repositories, I post a lot of snippets and personal projects that could help you!

Thanks for reading :)

--

--

Flávio Teixeira

Data engineer, gamer and addicted to technology. Currently working at Riot Games