I'm utilising a package which returns a nested dictionary. It feels awkward to access this return object in my class methods with the dictionary syntax, when everything else is in object syntax. Searching has brought me to the bunch / neobunch packages, which seems to achieve what I'm after. I've also seen namedtuples suggested but these do not easily support nested attributes and most solutions rely on using dictionaries within the namedtuple for nesting.
What would be a more natural way of achieving this?
data = {'a': 'aval', 'b': {'b1':{'b2a':{'b3a':'b3aval','b3b':'b3bval'},'b2b':'b2bval'}} }
print(data['b']['b1']['b2a']['b3b']) # dictionary access
# print(data.b.b1.b2a.b3b) # desired access
import neobunch
data1 = neobunch.bunchify(data)
print(data1.b.b1.b2a.b3b)
Access Nested Dictionary Items You can access individual items in a nested dictionary by specifying key in multiple square brackets. If you refer to a key that is not in the nested dictionary, an exception is raised. To avoid such exception, you can use the special dictionary get() method.
You can make use of the eval function in python. nestq will be "nest['b']['v']['y']" where nest is the nested dictionary. The eval builtin function executes the given string. However, it is important to be careful about possible vulnerabilities that arise from use of eval function.
In Python, a Nested dictionary can be created by placing the comma-separated dictionaries enclosed within braces.
The __dict__ in Python represents a dictionary or any mapping object that is used to store the attributes of the object. They are also known as mappingproxy objects. To put it simply, every object in Python has an attribute that is denoted by __dict__.
The following class would let you do what you want (works in Python 2 & 3):
class AttrDict(dict):
""" Dictionary subclass whose entries can be accessed by attributes (as well
as normally).
>>> obj = AttrDict()
>>> obj['test'] = 'hi'
>>> print obj.test
hi
>>> del obj.test
>>> obj.test = 'bye'
>>> print obj['test']
bye
>>> print len(obj)
1
>>> obj.clear()
>>> print len(obj)
0
"""
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
@classmethod
def from_nested_dicts(cls, data):
""" Construct nested AttrDicts from nested dictionaries. """
if not isinstance(data, dict):
return data
else:
return cls({key: cls.from_nested_dicts(data[key]) for key in data})
if __name__ == '__main__':
data = {
"a": "aval",
"b": {
"b1": {
"b2b": "b2bval",
"b2a": {
"b3a": "b3aval",
"b3b": "b3bval"
}
}
}
}
attrdict = AttrDict.from_nested_dicts(data)
print(attrdict.b.b1.b2a.b3b) # -> b3bval
Building on @martineau's excellent answer, you can make the AttrDict class to work on nested dictionaries without explicitly calling the from_nested_dict() function:
class AttrDict(dict):
""" Dictionary subclass whose entries can be accessed by attributes
(as well as normally).
"""
def __init__(self, *args, **kwargs):
def from_nested_dict(data):
""" Construct nested AttrDicts from nested dictionaries. """
if not isinstance(data, dict):
return data
else:
return AttrDict({key: from_nested_dict(data[key])
for key in data})
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
for key in self.keys():
self[key] = from_nested_dict(self[key])
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