trap setting attribute when the attribute is dict

G

Guest

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
 
A

Arnaud Delobelle

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):
.... 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]
........ 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
 
G

Guest

Arnaud Delobelle said:
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): ... 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]
...... 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,


 
A

Arnaud Delobelle

[...]
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:
.... 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
....
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
 
J

John Machin

Arnaud Delobelle said:
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
 
G

Guest

Arnaud Delobelle said:
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: ... 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
...
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.
 
G

Guest

John Machin said:
[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.... :(
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top