Object-like attribute access for nested dictionary

守給你的承諾、 提交于 2019-12-01 00:01:41

The following class would let you do what you want:

class AttrDict(dict):
    """ Dictionary subclass whose entries can be accessed by attributes
        (as well as normally).
    """
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

    @staticmethod
    def from_nested_dict(data):
        """ Construct nested AttrDicts from nested dictionaries. """
        if not isinstance(data, dict):
            return data
        else:
            return AttrDict({key: AttrDict.from_nested_dict(data[key])
                                for key in data})

data = {
    "a": "aval",
    "b": {
        "b1": {
            "b2b": "b2bval",
            "b2a": {
                "b3a": "b3aval",
                "b3b": "b3bval"
            }
        }
    }
}

data1 = AttrDict.from_nested_dict(data)
print(data1.b.b1.b2a.b3b)  # -> b3bval

A simple class, built on the basic object can be used:

class afoo1(object):
    def __init__(self, kwargs):
        for name in kwargs:
            val = kwargs[name]
            if isinstance(val, dict):
                val = afoo1(val)
            setattr(self,name,val)

I am borrowing the argparse.Namespace definition, tweaked to allow for nesting.

It would be used as

In [172]: dd={'a':'aval','b':{'b1':'bval'}}

In [173]: f=afoo1(dd)

In [174]: f
Out[174]: <__main__.afoo1 at 0xb3808ccc>

In [175]: f.a
Out[175]: 'aval'

In [176]: f.b
Out[176]: <__main__.afoo1 at 0xb380802c>

In [177]: f.b.b1
Out[177]: 'bval'

It could also have been defined with **kwargs (along with *args). A __repr__ definition might be nice as well.

As with other simple objects, attributes can be added, e.g. f.c = f (a recursive definition). vars(f) returns a dictionary, though it does not do any recursive conversion).

What about using __setattr__ method ?

>>> class AttrDict(dict):
...     def __getattr__(self, name):
...         if name in self:
...             return self[name]
... 
...     def __setattr__(self, name, value):
...         self[name] = self.from_nested_dict(value)
... 
...     def __delattr__(self, name):
...         if name in self:
...             del self[name]
... 
...     @staticmethod
...     def from_nested_dict(data):
...         """ Construct nested AttrDicts from nested dictionaries. """
...         if not isinstance(data, dict):
...             return data
...         else:
...             return AttrDict({key: AttrDict.from_nested_dict(data[key])
...                                 for key in data})
...         

>>> ad = AttrDict()
>>> ad
{}

>>> data = {'a': 'aval', 'b': {'b1':{'b2a':{'b3a':'b3aval','b3b':'b3bval'},'b2b':'b2bval'}} }

>>> ad.data = data
>>> ad.data
{'a': 'aval', 'b': {'b1': {'b2a': {'b3a': 'b3aval', 'b3b': 'b3bval'}, 'b2b': 'b2bval'}}}

>>> print(ad.data.b.b1.b2a.b3b)
    b3bval
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!