Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > trap setting attribute when the attribute is dict

Reply
Thread Tools

trap setting attribute when the attribute is dict

 
 
Guest
Posts: n/a
 
      09-03-2007
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
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









--
yosuke kimura
Center for Energy and Environmental Resources
The Univ. of Texas at Austin, USA
 
Reply With Quote
 
 
 
 
Arnaud Delobelle
Guest
Posts: n/a
 
      09-03-2007
On Sep 3, 7:00 pm, <(E-Mail Removed)> 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


 
Reply With Quote
 
 
 
 
Guest
Posts: n/a
 
      09-03-2007
Arnaud Delobelle <(E-Mail Removed)> wrote:
> On Sep 3, 7:00 pm, <(E-Mail Removed)> 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
 
Reply With Quote
 
Arnaud Delobelle
Guest
Posts: n/a
 
      09-03-2007
On Sep 3, 8:47 pm, <(E-Mail Removed)> wrote:

[...]

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


Why not simply have a method to update the dictionary that also keeps
the sum up to date? Something like that:

>>> class MyObj(object):

.... def __init__(self):
.... self._d = {}
.... self._sum = 0
.... def set_key(self, key, val):
.... self._sum += val - self._d.get(key, 0)
.... self._d[key] = val
.... def get_key(self, key):
.... return self._d[key]
.... def sum(self):
.... return self._sum
....
>>> a = MyObj()
>>> a.set_key(1, 2)
>>> a.sum()

2
>>> a.set_key('a', 10)
>>> a.set_key(1, 5)
>>> a.sum()

15
>>>


Of course this is only worth it if you need to use the sum often
enough.
If you update the dictionary a lot but only need the sum from time to
time, then it might not be worth it at all.

Of course you could subclass dict:

class MyDict(dict):
def __init__(self, *args, **kwargs):
self._sum = sum(self.itervalues())
def __setitem__(self, key, val):
self._sum += val - self.get(key, 0)
dict.__setitem__(self, key, val)
def sum(self):
return self._sum
# overload all other methods that mutate the dict
# to keep _sum up to date

>>> d = MyDict()
>>> d.sum()

0
>>> d['a']=5
>>> d.sum()

5
>>> d['b']=10
>>> d['a']=8
>>> d.sum()

18
>>>


HTH

--
Arnaud


 
Reply With Quote
 
John Machin
Guest
Posts: n/a
 
      09-04-2007
On Sep 4, 5:47 am, <(E-Mail Removed)> wrote:
> Arnaud Delobelle <(E-Mail Removed)> wrote:
> > On Sep 3, 7:00 pm, <(E-Mail Removed)> 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

 
Reply With Quote
 
Guest
Posts: n/a
 
      09-04-2007
Arnaud Delobelle <(E-Mail Removed)> wrote:
> On Sep 3, 8:47 pm, <(E-Mail Removed)> wrote:


> [...]


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


> Why not simply have a method to update the dictionary that also keeps
> the sum up to date? Something like that:


>>>> class MyObj(object):

> ... def __init__(self):
> ... self._d = {}
> ... self._sum = 0
> ... def set_key(self, key, val):
> ... self._sum += val - self._d.get(key, 0)
> ... self._d[key] = val
> ... def get_key(self, key):
> ... return self._d[key]
> ... def sum(self):
> ... return self._sum
> ...
>>>> a = MyObj()
>>>> a.set_key(1, 2)
>>>> a.sum()

> 2
>>>> a.set_key('a', 10)
>>>> a.set_key(1, 5)
>>>> a.sum()

> 15
>>>>


> Of course this is only worth it if you need to use the sum often
> enough.
> If you update the dictionary a lot but only need the sum from time to
> time, then it might not be worth it at all.


> Of course you could subclass dict:


> class MyDict(dict):
> def __init__(self, *args, **kwargs):
> self._sum = sum(self.itervalues())
> def __setitem__(self, key, val):
> self._sum += val - self.get(key, 0)
> dict.__setitem__(self, key, val)
> def sum(self):
> return self._sum
> # overload all other methods that mutate the dict
> # to keep _sum up to date


>>>> d = MyDict()
>>>> d.sum()

> 0
>>>> d['a']=5
>>>> d.sum()

> 5
>>>> d['b']=10
>>>> d['a']=8
>>>> d.sum()

> 18
>>>>


Thank you. I will go with subclassing method.

--
yosuke kimura
Center for Energy and Environmental Resources
The Univ. of Texas at Austin, USA
 
Reply With Quote
 
Guest
Posts: n/a
 
      09-04-2007
John Machin <(E-Mail Removed)> wrote:
> On Sep 4, 5:47 am, <(E-Mail Removed)> wrote:
>> Arnaud Delobelle <(E-Mail Removed)> wrote:
>> > On Sep 3, 7:00 pm, <(E-Mail Removed)> 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.

>>


[snip]

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


Thank you for the post.

I want the code to have fewer lines of code. That was my biggest
motivation for this. I have many of this dict with sum, each have <1000
elements. all of them share the same keys. I do many
addition/subtraction/divisions by each elements (yes, division makes the
elements not being able to summed). so in my code i have repeated lines
that works on each elements and then on the sum. i made a dict to take
care of adding elements by elements. but i still had two lines of code,
one for dict elements, and one for the sum.

my code was originally in fortran and it has like thousands of lines,
obscuring the mathematics that i want to do. i need to modify math
often while i use the code (i dont know exactly what math i will need at
this point), so i want to the code to be able to show the math
clearly. ideally i want to this to be somthing like

c = a + b
d = 1 / c

and each of a, b, c, d knows how to operates on each elements, and also
keep track of the sum.

I think i will settle for extending dict to have sum property and keep
track of it .





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



not quite getting this....

> HTH,
> John



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

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
dict.items() vs dict.iteritems and similar questions Drew Python 19 03-15-2007 09:23 PM
dict.has_key(x) versus 'x in dict' Paul Melis Python 48 12-15-2006 05:55 PM
Inconsistency in dictionary behaviour: dict(dict) not calling __setitem__ Almad Python 8 12-14-2006 07:37 PM
dict!ident as equivalent of dict["ident"] Alexander Kozlovsky Python 5 05-22-2006 08:06 AM
Re: dict->XML->dict? Or, passing small hashes through text? Skip Montanaro Python 0 08-15-2003 03:46 PM



Advertisments