I've found that setting integer variables all at once works as expected:
foo = bar = cue = 0
foo = 1
bar = 2
print(foo, bar, cue)
1 2 0
However, when doing the same thing with a list type, it updates all of the vars at the same time. The resulting vars will always equal one another.
foo = bar = cue = []
foo = [1]
bar = [2]
print(foo, bar, cue)
[1, 2] [1, 2] [1, 2]
Why does the behavior differ depending on the variable type? Thanks much.
CodePudding user response:
The augmented assignment operator =
hooks into the datamodel magic method __iadd__
("in-place addition"). If this method doesn't exist, it falls back to using the regular __add__
method. From the docs:
These 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.
It happens that int
doesn't define int.__iadd__
, because it does not make sense to do anything "in-place" on an immutable type.
>>> int.__iadd__
AttributeError: type object 'int' has no attribute '__iadd__'
However, list
does implement it, and "extends" the existing list with elements taken from iterating the right hand side:
>>> list.__iadd__
<slot wrapper '__iadd__' of 'list' objects>
So when foo == 0
, the augmented assignment foo = 1
does something like this:
foo = foo.__add__(1) # returns a different integer instance
Whereas when foo == []
the augmented assigmnent foo = [1]
does something more like this:
foo = foo.__iadd__([1]) # modifies foo in-place and returns foo again
It follows that foo
, bar
, and cue
are names bound to different integer objects in the first case, but bound to the same list instance in the second case.