I am using Python 3.5 and I have a problem assigning values to a dictionary key. The structure of my dictionary looks like this:
dict_var = {'file':
{'index':
{'flag':
{'flag_key': 'False'},
'attr':
{'attr_key': 'attr_val'},
'path':
{'path_key': 'path_val'},
}
}
}
I get the KeyError: 1, if I change the nested key 'index'
like this:
dict_var['file']['1']['flag'] = 'some value'
dict_var['file']['2']['flag'] = 'some value'
dict_var['file']['3']['flag'] = 'some value'
dict_var['file']['4']['flag'] = 'some value'
Or if I try to change the nested key 'flag'
:
dict_var['file']['index']['flag_2']['flag_key'] = 'some value'
Is there a way to assign a new name to a nested key, but keep the structure of the following sub keys and values, like in my example?
You can use a nested defaultdict
, like this:
from collections import defaultdict
ndefaultdict = lambda:defaultdict(ndefaultdict)
dict_var = ndefaultdict()
dict_var['file']['1']['flag'] = 'some value'
dict_var['file']['2']['flag'] = 'some value'
dict_var['file']['3']['flag'] = 'some value'
dict_var['file']['4']['flag'] = 'some value'
You can then write a simple loop to transfer the information from your original dict into the nested dict. An example solution:
from collections import defaultdict
def ndefaultdict(orig_dict):
l = lambda: defaultdict(l)
out = l()
def n_helper(orig_dict, nesteddict):
for k, v in orig_dict.items():
if isinstance(v, dict):
n_helper(v, nesteddict[k])
else:
nesteddict[k] = v
return nesteddict
return n_helper(orig_dict, out)
# dict_var is the original dictionary from the OP.
new_dict = n_defaultdict(dict_var)
new_dict['foo']['bar']['baz'] = 'It works!!'
print( new_dict['file']['index']['attr']['attr_key']) # attr_val
EDIT:
Looking at this SO thread, I found two other elegant solutions:
Short solution with defaultdict
from collections import defaultdict
def superdict(arg=()):
update = lambda obj, arg: obj.update(arg) or obj
return update(defaultdict(superdict), arg)
>>> d = {"a":1}
>>> sd = superdict(d)
>>> sd["b"]["c"] = 2
Using a custom NestedDict class.
>>> class NestedDict(dict):
... def __getitem__(self, key):
... if key in self: return self.get(key)
... return self.setdefault(key, NestedDict())
>>> eggs = NestedDict()
>>> eggs[1][2][3][4][5]
{}
>>> eggs
{1: {2: {3: {4: {5: {}}}}}}