trap setting attribute when the attribute is dict

yosuke at ccwf.cc.utexas.edu yosuke at ccwf.cc.utexas.edu
Mon Sep 3 21:47:55 CEST 2007


Arnaud Delobelle <arnodel at googlemail.com> wrote:
> On Sep 3, 7:00 pm, <yos... at ccwf.cc.utexas.edu> wrote:
>>
>> I want to do something like this.  My class/instance has a dict as a
>> property.  I want the instance to catch the change in the dict (change
>> in some values, addition/deletion of key/value etc) to be recognized by
>> the class instance.  
>>
>> How can I do this?  Any suggestions are very well appreciated.
>>
>> Here is an example of what I want my class to behave:
>>
>> class test(object):
>>         def __init__(self):
>>                 self._d = {}
>>                 self._changed = False
>>         def getd(self):
>>                 print 'called getd'
>>                 return self._d
>>         # dont know what to do next
>>         def setd(self,val):
>>                 print 'called setd', key, val
>>                 self._d[key] = val

> Where does the 'key' come from?  Perhaps you need to look further into
> how properties work.

This obviously doesn't work...

>>                 self._changed = True
>>         d = property(getd,setd,None,None)
>>
>>         def getc(self):
>>                 return self._changed
>>         changed = property(getc,None,None,None)
>>
>> if __name__ == '__main__':
>>         obj = test()
>>         print 'obj.changed = ', obj.changed
>>         print
>>
>>         # I want obj to know that its propety d being changed here
>>         print "t.d['a'] = 1"
>>         obj.d['a'] = 1
>>         print
>>
>>         # I want the "changed" property to be True
>>         print 'obj.changed = ', obj.changed
>>

> You can't do that with plain dicts, and I'm not sure it is often a
> good idea.  However you could create a class that behaves like a dict
> but calls a function each time an item is set, e.g. (made up
> terminology):

>>>> class TriggerDict(object):
> ...     def __init__(self, trigger, val=None):
> ...             self.trigger = trigger
> ...             self.dict_ = val or {}
> ...     def __setitem__(self, key, val):
> ...             self.trigger(self, key, val)
> ...             self.dict_[key] = val
> ...     def __getitem__(self, key):
> ...             return self.dict_[key]
> ...
>>>> def trigger(d, k, v):
> ...     print '%s => %s' % (k, v)
> ...
>>>> td = TriggerDict(trigger)
>>>> td['spanish'] = 'inquisition' # see side effect below.
> spanish => inquisition
>>>> td['spanish']
> 'inquisition'
>>>>

> Obviously your trigger function would set the _changed attribute of
> the test object instead.  And again it is probably not a good idea
> unless you know exactly what you are doing.  If it was me, I'd try to
> rethink my design instead.

Thank you for suggestion, Arnaud.

Since you are discouraging this idea of trigger, may I ask an advice of
if my intention was legitimate one or not?

My intention was to have a propery 'sum' in my object, and which has sum
of all the values() of the dict (i have code to make sure that the value
of dict are all numeric).  I could just the propery being calculated
everytime the property got __getattr__.  But I thought that it was
inefficient to calculate the same number over and over when the value is
already known.  So I was thiking of calculating the number only when the
dict got modified.

I also experimented with the idea of subclassing dict itself to
calculate the sum.  Is this what would be better solution?

Thank you again,



> --
> Arnaud



-- 
yosuke kimura
Center for Energy and Environmental Resources
The Univ. of Texas at Austin, USA



More information about the Python-list mailing list