如何定义一个超级强大的类样式dict对象?

2024-04-25 22:11:55 发布

您现在位置:Python中文网/ 问答频道 /正文

假设满足我需要的对象名为classdic,那么{}类的实例的函数是:

  1. 查询、更新、添加和删除数据都可以通过类样式的方式和dict样式的方式(称为“两种方式”)来实现。

  2. 当属性或键不存在时,类dic的实例可以自动构建它,并使其等于instance和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}

Tags: 实例in方式onefourwaysfivetwo
3条回答

子类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

这将而不是自动创建自身的嵌套实例;您需要遍历输入字典并自己创建嵌套对象。在

但它确实提供了属性访问和默认值:

^{pr2}$

要从现有字典构建树,请使用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

如果你想做

cdic.two = 2 

您还应该重写setattr

^{pr2}$

这是Martijn Pieters的answer的变体,它是answer的变体(它本身是this的变体,它基于James Robert的blog entry)。然而,与Martijn不同的是,it会自动创建自身的嵌套实例。还添加了一个自定义__repr__()。在

from collections import defaultdict, Mapping

class classdict(defaultdict):
    def __init__(self, *args, **kwargs):
        super(classdict, self).__init__(*args, **kwargs)
        self.__dict__ = self

    def __getattr__(self, name):
        return self[name]  # trigger default

    def __missing__(self, key):
        default = (None if self.default_factory is None else
                   self.default_factory())
        self[key] = classdict.from_dict({key: default},
                                        default=self.default_factory)
        return self[key]

    def __repr__(self):
        return '{}({}, default={})'.format(self.__class__.__name__,
                                           dict(self.__dict__),  # no recursion
                                           self.default_factory)
    @classmethod
    def from_dict(cls, d, default=lambda: None):
        cdic = cls(default)
        for key, value in d.iteritems():
            cdic[key] = (value if not isinstance(value, Mapping)
                         else cls.from_dict(value, default=default))
        return cdic

if __name__ == '__main__':

    dic={'one': 1,
         'two': {'four': 4,
                 'five': {'six': 6,
                          'seven': 7}
                },
         'three': 3
        }

    cdic = classdict.from_dict(dic, default=lambda: 100)

    print 'cdic.one:', cdic.one
    print 'cdic.two:', cdic.two
    print 'cdic.two.five.six:', cdic.two.five.six
    print "cdic['two']['five']['six']:", cdic['two']['five']['six']
    print "cdic['two']['five']['six'] = 7"
    cdic['two']['five']['six'] = 7
    print 'cdic.two.five.six:', cdic.two.five.six
    print 'cdic.two.five.six = 8'
    cdic.two.five.six = 8
    print "cdic['two']['five']['six']:", cdic['two']['five']['six']
    print "cdic['two']['five']['eight'] = 8"
    cdic['two']['five']['eight'] = 8
    print 'cdic.two.five.eight:', cdic.two.five.eight
    print 'cdic.two.five.nine = 9'
    cdic.two.five.nine = 9
    print "cdic['two']['five']['nine']:", cdic['two']['five']['nine']
    print "cdic['ten']:", cdic['ten']
    print 'cdic.ten:', cdic.ten
    print 'cdic.eleven:', cdic.eleven
    print "cdic['eleven']:", cdic['eleven']
    print "final cdic:\n    ", cdic

相关问题 更多 >

    热门问题