I would like to access a dictionary programmatically. I know how to do this with a recursive function, but is there a simpler way?
example = {'a': {'b': 'c'},
'1': {'2': {'3': {'4': '5'}}}}
keys = ('a', 'b')
example[keys] = 'new'
# Now it should be
# example = {'a': {'b': 'new'},
# '1': {'2': {'3': {'4': '5'}}}}
keys = ('1', '2', '3', '4')
example[keys] = 'foo'
# Now it should be
# example = {'a': {'b': 'new'},
# '1': {'2': {'3': {'4': 'foo'}}}}
keys = ('1', '2')
example[keys] = 'bar'
# Now it should be
# example = {'a': {'b': 'new'},
# '1': {'2': 'bar'}}
{'a': {'r': 100, 's': 2, 't': 3}, 'b': {'u': 1, 'v': {'x': 1, 'y': 2, 'z': 3}, 'w': 3}} To access nested dictionary items via a list of keys with Python, we can use the reduce function with the operator.getitem method to get the dictionary item with the array of keys forming the path to the dictionary item.
Here, the nested_dict is a nested dictionary with the dictionary dictA and dictB. They are two dictionary each having own key and value. We're going to create dictionary of people within a dictionary. When we run above program, it will output:
Slicing Nested Dictionary is not possible. We can shrink or grow nested dictionary as need. Like Dictionary, it also has key and value. Dictionary are accessed using key.
Using the for loops, we can iterate through each elements in a nested dictionary. Example 7: How to iterate through a Nested dictionary? When we run above program, it will output: In the above program, the first loop returns all the keys in the nested dictionary people. It consist of the IDs p_id of each person.
What you seem to want to do is define your own class of dictionary that supports this kind of indexing. We can attain a fairly neat syntax by using the fact that when you do d[1, 2, 3]
, Python actually passes the tuple (1, 2, 3)
to __getitem__
.
class NestedDict:
def __init__(self, *args, **kwargs):
self.dict = dict(*args, **kwargs)
def __getitem__(self, keys):
# Allows getting top-level branch when a single key was provided
if not isinstance(keys, tuple):
keys = (keys,)
branch = self.dict
for key in keys:
branch = branch[key]
# If we return a branch, and not a leaf value, we wrap it into a NestedDict
return NestedDict(branch) if isinstance(branch, dict) else branch
def __setitem__(self, keys, value):
# Allows setting top-level item when a single key was provided
if not isinstance(keys, tuple):
keys = (keys,)
branch = self.dict
for key in keys[:-1]:
if not key in branch:
branch[key] = {}
branch = branch[key]
branch[keys[-1]] = value
Here are examples of usage
# Getting an item
my_dict = NestedDict({'a': {'b': 1}})
my_dict['a', 'b'] # 1
# Setting an item
my_dict = NestedDict()
my_dict[1, 2, 3] = 4
my_dict.dict # {1: {2: {3: 4}}}
# You can even get a branch
my_dict[1] # NestedDict({2: {3: 4}})
my_dict[1][2, 3] # 4
You can then make NestedDict
implementation richer by also defining __iter__
, __len__
and __contains__
.
Also, this can be integrated fairly easily in your code since any pre-existing dictionary can be turned into a nested one by doing NestedDict(your_dict)
.
Make traversal a method of your dictionary. You can do this easily by subclassing dict
.
The algorithm for traversing is courtesy of @MartijnPeters (upvote there).
import operator
class ndict(dict):
def get_traverse(self, mapList):
return reduce(operator.getitem, mapList, self)
def set_traverse(self, mapList, value):
self.get_traverse(mapList[:-1])[mapList[-1]] = value
d = ndict({'a': {'b': 'c'}, '1': {'2': {'3': {'4': '5'}}}})
d.get_traverse(['a', 'b']) # 'c'
d.set_traverse(['a', 'b'], 4) # {'a': {'b': 4}, '1': {'2': {'3': {'4': '5'}}}}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With