I'm working on a Python script where I'm given lists of strings of the format: ['key1', 'key2', 'key2.key21.key211', 'key2.key22', 'key3']
.
Each value in the list corresponds to an entry in a dictionary, and for entries structured like 'key2.key21.key211'
, they correspond to (in this example), a key 'key211'
nested within 'key21'
, itself nested inside 'key2'
.
The above list corresponds to the dictionary:
x = {
'key1' : 'value1',
'key2' : {
'key21' : {
'key211': 'value211'
},
'key22' : 'value22'
},
'key3' : 'value3'
}
The names are not necessarily as regular as key(n)+
; they can be of the form food.vegetables.potato
, for example. The only guarantees I have is that the key names themselves, in the dictionary, do not contain the .
character, and that the dictionary definitely contains all the entries referenced in the original list.
My question is, given such a list of strings, how do I programmatically access the corresponding entries in a dictionary? I can think of a solution using eval()
, as well as one using just a traversal/search, but I want to avoid calls to eval()
, and I get the impression that a traversal with comparisons would be slow (since dict
s aren't search trees), and would entail a lot of nasty exception handling.
One approach is to write a function to access keys in nested dicts.
def deep_access(x,keylist):
val = x
for key in keylist:
val = val[key]
return val
s = 'key2.key21.key211'
print deep_access(x,s.split('.'))
result:
value211
Another approach, if you want to use similar syntax as a normal dictionary access you could subclass dict
and override __getitem__
to allow for nested access when a tuple of keys is provided:
class NestedDict(dict):
def __getitem__(self,keytuple):
# if key is not a tuple then access as normal
if not isinstance(keytuple, tuple):
return super(NestedDict,self).__getitem__(keytuple)
d = self
for key in keytuple:
d = d[key]
return d
>>> nd = NestedDict(x)
>>> nd['key2']
{'key22': 'value22', 'key21': {'key211': 'value211'}}
>>> nd['key2','key22']
'value22'
>>> nd['key2','key21']
{'key211': 'value211'}
>>> nd['key2','key21','key211']
'value211'
You can then similarly implement __setitem__
and __delitem__
as needed.
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