假设满足我需要的对象称为classdic
,则类classdic
的实例的功能为:
查询,更新,添加和删除数据都可以用类样式方式和dict样式方式(称为“两种方式”)来实现。
当属性或键不存在时,classdic实例可以自动构建它并使它等于实例和dict上的默认值,因此我们可以用两种方式查询它(注意:不添加,仅查询)。
那么,如何实现此类?
下面的示例显示此类的实例如何工作:
dic={'one':1,
'two':{'four':4,'five':{'six':6,'seven':7}},
'three':3}
cdic=classdic(dic,default=100)
-------------------query in two ways-------------------------------------------
>>> cdic.one
1
>>> cdic.two
{'four':4,'five':{'six':6,'seven':7}}
>>> cdic.two.five.six
6
>>> cdic['two']['five']['six']
6
-------------------update in two ways-------------------------------------------
>>> cdic['two']['five']['six']=7
>>> cdic.two.five.six
7
>>> cdic.two.five.six=8
>>> cdic['two']['five']['six']
8
-------------------add in two ways-------------------------------------------
>>> cdic['two']['five']['eight']=8
>>> cdic.two.five.eight
8
>>> cdic.two.five.nine=9
>>> cdic['two']['five']['nine']
9
-------------------query default in two ways-------------------------------------------
>>> print cdic['ten']
100
>>> cdic.ten
100
>>> print cdic.eleven
100
>>> cdic['eleven']
100
-------------------the final state of cdic-------------------------------------------
>>> cdic
{'eleven': 100, 'three': 3, 'two': {'four': 4, 'five': {'nine': 9, 'seven': 7, 'six': 8, 'eight': 8}}, 'ten': 100, 'one': 1}
最佳答案
子类collections.defaultdict()
:
from collections import defaultdict, Mapping
class default_attribute_dict(defaultdict):
def __init__(self, *args, **kwargs):
super(default_attribute_dict, self).__init__(*args, **kwargs)
self.__dict__ = self
def __getattr__(self, name):
# trigger default
return self[name]
@classmethod
def from_dictionaries(cls, d, default=lambda: None):
cdic = cls(default)
for key, value in d.iteritems():
if isinstance(value, Mapping):
value = cls.from_dictionaries(value, default=default)
cdic[key] = value
return cdic
这不会自动创建其自身的嵌套实例。您需要遍历输入字典并自己创建嵌套对象。
但是它确实提供了属性访问和默认值:
>>> cdic = default_attribute_dict(lambda: 100)
>>> cdic.hundred
100
>>> cdic['ten'] = 10
>>> cdic.ten
10
>>> cdic['ten']
10
要从现有字典构建树,请使用
from_dictionaries()
类方法:>>> cdic = default_attribute_dict.from_dictionaries(dic, default=lambda: 100)
>>> cdic
defaultdict(<function <lambda> at 0x109998848>, {'one': 1, 'three': 3, 'two': defaultdict(<function <lambda> at 0x109998848>, {'four': 4, 'five': defaultdict(<function <lambda> at 0x109998848>, {'seven': 7, 'six': 6})})})
>>> cdic.two.four
4
注意,字典上的键可以掩盖方法。在插入与字典方法匹配的键时,请记住以下几点:
>>> cdic = default_attribute_dict.from_dictionaries(dic, default=lambda: 100)
>>> cdic.keys
<built-in method keys of default_attribute_dict object at 0x7fdd0bcc9ac0>
>>> cdic['keys']
100
>>> cdic.keys
100
>>> cdic.keys()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable