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?
iadd() :- This function is used to assign and add the current value. This operation does “a+=b” operation. Assigning is not performed in case of immutable containers, such as strings, numbers and tuples.
Python property() function returns the object of the property class and it is used to create property of a class. Parameters: fget() – used to get the value of attribute. fset() – used to set the value of attribute.
Use Python's vars() to Print an Object's Attributes The dir() function, as shown above, prints all of the attributes of a Python object.
__iadd__
will only be looked for on the value returned from __get__
. You need to make __get__
(or the property getter) return an object (or a proxy object) with __iadd__
.
@property
def x(self):
proxy = IProxy(self._x)
proxy.parent = self
return proxy
class IProxy(int, object):
def __iadd__(self, val):
self.parent.iadd_x(val)
return self.parent.x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With