trap setting attribute when the attribute is dict

Arnaud Delobelle arnodel at googlemail.com
Mon Sep 3 14:47:16 EDT 2007


On Sep 3, 7:00 pm, <yos... at ccwf.cc.utexas.edu> wrote:
> Hello all,
>
> I have a question which might be simple or need some work around.
>
> 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.

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

HTH

--
Arnaud





More information about the Python-list mailing list