我正在使用一个返回嵌套字典的包。 当其他所有内容都在对象语法中时,使用字典语法在类方法中访问此返回对象会感到很尴尬。 搜索带给我一堆/新推出的套餐,这似乎达到了我之后的目标。我也看到过namedtuples的建议,但这些不容易支持嵌套属性,大多数解决方案依赖于在namedtuple中使用字典进行嵌套。
实现这一目标的更自然的方式是什么?
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)
答案 0 :(得分:4)
以下课程可以让你做你想做的事:
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
答案 1 :(得分:0)
可以使用基于基本对象构建的简单类:
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)
我借用argparse.Namespace
定义,调整以允许嵌套。
它将用作
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'
也可以使用**kwargs
(以及*args
)进行定义。 __repr__
定义也可能很好。
与其他简单对象一样,可以添加属性,例如f.c = f
(递归定义)。 vars(f)
返回字典,但它不进行任何递归转换。)
答案 2 :(得分:0)
使用__setattr__
方法怎么样?
>>> 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
答案 3 :(得分:0)
基于@martineau's的出色答案,您可以使AttrDict类在嵌套字典上工作,而无需显式调用from_nested_dict()函数:
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])
答案 4 :(得分:0)
json.loads
有一个有趣的参数,称为object_hook
,如果所有字典值都是JSON可序列化的,即
import json
from types import SimpleNamespace
data = {'a': 'aval', 'b': {'b1':{'b2a':{'b3a':'b3aval','b3b':'b3bval'},'b2b':'b2bval'}}}
data1= json.loads(
json.dumps(data), object_hook=lambda d: SimpleNamespace(**d)
)
print(data1.b.b1.b2a.b3b) # -> b3bval
如果Guido在听,我认为SimpleNamespace
应该使用recursive
参数,以便您可以执行data1 = SimpleNamespace(recursive=True, **data)
。
答案 5 :(得分:0)