Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object-like attribute access for nested dictionary

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)
like image 510
Tim B Avatar asked Jun 26 '16 01:06

Tim B


People also ask

How do I access nested dict values?

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.

How do you access a dictionary nested in a list?

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.

How do you make a nested dictionary dynamically in Python?

In Python, a Nested dictionary can be created by placing the comma-separated dictionaries enclosed within braces.

What is the __ dict __ attribute of an object in Python?

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__.


2 Answers

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

like image 182
martineau Avatar answered Nov 10 '22 09:11

martineau


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])
like image 21
Saravana Kumar Avatar answered Nov 10 '22 09:11

Saravana Kumar