trap setting attribute when the attribute is dict

John Machin sjmachin at lexicon.net
Mon Sep 3 20:10:53 EDT 2007


On Sep 4, 5:47 am, <yos... at ccwf.cc.utexas.edu> wrote:
> Arnaud Delobelle <arno... 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?
>

And what's wrong with calculating the value when you need it ...

def thedictsum(self):
    return sum(self.thedict.itervalues())

How big will the dict be, how often will it be updated, how often will
the sum be required?

Have you done timings of any of the options?

You say you have code to check that the values are numeric; why not
put this together with maintenance of the sum into a method which
clients must use to update the dict?

BTW, my motto:

"__" == "Danger, Will Robinson!" == "Wrong way, go back" :-)

HTH,
John




More information about the Python-list mailing list