Skip to content Skip to sidebar Skip to footer

How To Define A Super Powerful Class-style Dict Object?

Assume that the object meeting my need is called classdic, then the functions of an instance of class classdic are: Query, update, add, and delete data can be all realized in clas

Solution 1:

Subclass collections.defaultdict():

from collections import defaultdict, Mapping

classdefault_attribute_dict(defaultdict):
    def__init__(self, *args, **kwargs):
        super(default_attribute_dict, self).__init__(*args, **kwargs)
        self.__dict__ = self

    def__getattr__(self, name):
        # trigger defaultreturn self[name]

    @classmethoddeffrom_dictionaries(cls, d, default=lambda: None):
        cdic = cls(default)
        for key, value in d.iteritems():
            ifisinstance(value, Mapping):
               value = cls.from_dictionaries(value, default=default)
            cdic[key] = value
        return cdic

This will not automatically create nested instances of itself; you'll need to loop over the input dictionary and create nested objects yourself.

But it does offer attribute access and default values:

>>>cdic = default_attribute_dict(lambda: 100)>>>cdic.hundred
100
>>>cdic['ten'] = 10>>>cdic.ten
10
>>>cdic['ten']
10

To build your tree from an existing dictionary, use the from_dictionaries() class method:

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

Note that keys on the dictionary can mask methods; keep that in mind when inserting keys that match dictionary methods:

>>> 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'objectisnotcallable

Solution 2:

If you want to be able to do

cdic.two = 2

You should also override __setattr__

def__setattr__(self, name, val):
    self[name] = val

Solution 3:

Here's a variation of Martijn Pieters' answer which is a variation of this answer (which itself is a variation of this, which is based on a blog entry by James Robert). However, unlike the Martijn's it will automatically create nested instances of itself. A custom__repr__()has also been added.

from collections import defaultdict, Mapping

classclassdict(defaultdict):
    def__init__(self, *args, **kwargs):
        super(classdict, self).__init__(*args, **kwargs)
        self.__dict__ = self

    def__getattr__(self, name):
        return self[name]  # trigger defaultdef__missing__(self, key):
        default = (Noneif self.default_factory isNoneelse
                   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)
    @classmethoddeffrom_dict(cls, d, default=lambda: None):
        cdic = cls(default)
        for key, value in d.iteritems():
            cdic[key] = (value ifnotisinstance(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'] = 7print'cdic.two.five.six:', cdic.two.five.six
    print'cdic.two.five.six = 8'
    cdic.two.five.six = 8print"cdic['two']['five']['six']:", cdic['two']['five']['six']
    print"cdic['two']['five']['eight'] = 8"
    cdic['two']['five']['eight'] = 8print'cdic.two.five.eight:', cdic.two.five.eight
    print'cdic.two.five.nine = 9'
    cdic.two.five.nine = 9print"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

Solution 4:

After studying all the answers,I wrote the solution by myself.

It meets my needs well and no "import xxx" is required,also kind to print.

(I think mine is better than this one I have planned to share yesterday)

my solution:

classDictObj(dict):
    default=Nonedef__init__(self, dic, default):
        DictObj.default = default
        for key,value in dic.items():
            ifisinstance(value,dict):
                self.__setattr__(key, DictObj(value,DictObj.default))
            else:
                self.__setattr__(key, value)  
    def__getitem__(self, key):
        return self.__getattr__(key )

    def__setitem__(self, key, value):
        self.__setattr__(key,value)

    def__getattr__( self ,key ):
        if key notin self:
            self.__setattr__(key,DictObj.default)
        return self.__dict__[key] 

    def__setattr__( self ,key ,value ):
        self.__dict__[key]=value
        dict.__setitem__(self, key, value)

    defprintself(self):
        print self     

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

cdic=DictObj(dic,100)

print'-------------------the start state of cdic-------------------------------------------'print cdic

print'-------------------query in two ways-------------------------------------------'print'cdic.two.five-->',cdic.two.five
print"cdic['two']['five']-->",cdic['two']['five']
print'cdic.two.five.six-->',cdic.two.five.six
print"cdic['two']['five']['six']-->",cdic['two']['five']['six']

print'-------------------update in two ways-------------------------------------------'
cdic['two']['five']['six']=7print"cdic['two']['five']['six']=7"print"cdic.two.five.six-->",cdic.two.five.six 

cdic.two.five.six=6print"cdic.two.five.six=6"print"cdic['two']['five']['six']-->",cdic['two']['five']['six']

print'-------------------add in two ways-------------------------------------------'

cdic['two']['five']['eight']=8print"cdic['two']['five']['eight']=8"print"cdic.two.five.eight-->",cdic.two.five.eight

cdic.two.five.nine=9print"cdic.two.five.nine=9"print"cdic['two']['five']['nine']-->",cdic['two']['five']['nine']

print'-------------------query default in two ways-------------------------------------------'print"cdic['ten']-->",cdic['ten']
print"cdic.eleven-->",cdic.eleven
print"cdic.two.five.twelve-->",cdic.two.five.twelve
print'-------------------the final state of cdic-------------------------------------------'print cdic,'\n'
cdic.printself()

the result:

-------------------the start state of cdic-------------------------------------------
{'one': 1, 'three': 3, 'two': {'four': 4, 'five': {'seven': 7, 'six': 6}}}
-------------------query in two ways-------------------------------------------
cdic.two.five--> {'seven': 7, 'six': 6}
cdic['two']['five']--> {'seven': 7, 'six': 6}
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=6
cdic['two']['five']['six']--> 6-------------------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-------------------------------------------
cdic['ten']--> 100
cdic.eleven--> 100
cdic.two.five.twelve--> 100-------------------the final state of cdic-------------------------------------------
{'eleven': 100, 'one': 1, 'three': 3, 'ten': 100, 'two': {'four': 4, 'five': {'nine': 9, 'seven': 7, 'six': 6, 'eight': 8, 'twelve': 100}}}

{'eleven': 100, 'one': 1, 'three': 3, 'ten': 100, 'two': {'four': 4, 'five': {'nine': 9, 'seven': 7, 'six': 6, 'eight': 8, 'twelve': 100}}}

Post a Comment for "How To Define A Super Powerful Class-style Dict Object?"