With immutable types like integers, a -= b
is the same thing as a = a - b
: It creates a new value, a - b
, and re-binds the name a
to refer to that new value instead of the old one.
But with mutable types like sets, a -= b
changes the value that a
is pointing to in-place. (It also re-binds a
to the same value it's already referring to, but that's not important.)
The best way to see this is by looking at the object's identity:
>>> s1 = set(range(3))
>>> s2 = s1
>>> s1, id(s1), s2, id(s2)
({0, 1, 2}, 4303749432, {0, 1, 2}, 4303749432)
>>> s1 -= {1}
>>> s1, id(s1), s2, id(s2)
({0, 2}, 4303749432, {0, 2}, 4303749432)
>>> s1 = s1 - {2}
>>> s1, id(s1), s2, id(s2)
({0}, 4303749664, {0, 2}, 4303749432)
Notice that the -=
leaves s1
still referring to the same set as s2
, and changes that set; the -
leaves s1
referring to a brand-new set with a different id
, and doesn't affect s2
.
Under the covers, a = a - b
is roughly* equivalent to a = a.__sub__(b)
, while a -= b
is equivalent to a = a.__isub__(b)
. Except that if there is no __isub__
method, a -= b
just uses __sub__
instead.
The fact that __isub__
changes the value, while __sub__
returns a new value, isn't really enforced by the language, but it's something that's true of all built-in and stdlib types, and expected to be true of any custom types. It's described in Emulating numeric types in the docs:
These [__ifoo__
] methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self). If a specific method is not defined, the augmented assignment falls back to the normal methods. For instance, to execute the statement x += y
, where x is an instance of a class that has an __iadd__()
method, x.__iadd__(y)
is called. If x is an instance of a class that does not define a __iadd__()
method, x.__add__(y)
and y.__radd__(x)
are considered, as with the evaluation of x + y
.
* It's not exactly equivalent because of (a) __rsub__
, (b) types implemented in C (like set
), and (c) rules for looking up certain special methods being different from normal methods.