Setting multiple Python variables at once does not always work as expected

Question:

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.

Asked By: Rino Bino

||

Answers:

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.

Answered By: wim
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.