I'm trying to create a Python property where in-place adding is handled by a different method than retrieving the value, adding another value and reassigning. So, for a property x
on an object o
,
o.x += 5
should work differently than
o.x = o.x + 5
The value of o.x
should be the same in the end, so as not to confuse people's expectations, but I want to make the in-place add more efficient. (In reality the operation takes a lot more time than simple addition.)
My first idea was to define, in the class,
x = property(etc. etc.)
x.__iadd__ = my_iadd
But this raises an AttributeError, presumably because property
implements __slots__
?
My next attempt uses a descriptor object:
class IAddProp(object):
def __init__(self):
self._val = 5
def __get__(self, obj, type=None):
return self._val
def __set__(self, obj, value):
self._val = value
def __iadd__(self, value):
print '__iadd__!'
self._val += value
return self
class TestObj(object):
x = IAddProp()
#x.__iadd__ = IAddProp.__iadd__ # doesn't help
>>> o = TestObj()
>>> print o.x
5
>>> o.x = 10
>>> print o.x
10
>>> o.x += 5 # '__iadd__!' not printed
>>> print o.x
15
As you can see, the special __iadd__
method is not called. I'm having trouble understanding why this is, although I surmise that the object's __getattr__
is somehow bypassing it.
How can I do this? Am I not getting the point of descriptors? Do I need a metaclass?