JPNotADragon JPNotADragon - 1 month ago 5
Python Question

How to use the += operator on a property that doesn't have a setter?

I'm getting a

Can't set attribute
error when I'm using the
+=
operator on a read-only property that is of a type for which I've defined a
__iadd__()
method.

Simplified (but runnable) version of my code:

class Emitter(list):
def __iadd__(self, other):
self.append( other )
return self

class Widget:
def __init__(self):
self._on_mouseenter = Emitter()

@property
def on_mouseenter(self): return self._on_mouseenter


my_widget = Widget()
my_widget.on_mouseenter += lambda source: print("on_mouseenter!")


The last line produces the error. It goes away if I add the following line to the definition of
Widget
:

@on_mouseenter.setter
def on_mouseenter(self, value): pass


(Runnable at https://repl.it/EONf/0)

This behaviour seems strange on two accounts. First, I thought that Python passes objects by reference, so why should the property have to be readable? And second, how come that my dummy setter even works?

Max Max
Answer

__iadd__ returns a replacement object to be rebound to the variable. This of course requires a setter.

In this case it works because you're ignoring the set, but still leaving the original object in place, which you've changed in place.

This behavior is required because some objects are immutable, but in place add still works on them.

i += 5 takes the number i is bound to, adds 5 to it, and rebinds i to the NEW result number. That is, it is exactly equivalent to i = i + 5, which has an assignment in it.