Is i = i + n truly the same as i += n? [duplicate]

They don’t have to be the same.

Using the + operator calls the method __add__ while using the += operator calls __iadd__. It is completely up to the object in question what happens when one of these methods is called.

If you use x += y but x does not provide an __iadd__ method (or the method returns NotImplemented), __add__ is used as a fallback, meaning that x = x + y happens.

In the case of lists, using l += iterable actually extends the list l with the elements of iterable. In your case, every character from the string (which is an iterable) is appended during the extend operation.

Demo 1: using __iadd__

>>> l = []
>>> l += 'table'
>>> l
['t', 'a', 'b', 'l', 'e']

Demo 2: using extend does the same

>>> l = []
>>> l.extend('table')
>>> l
['t', 'a', 'b', 'l', 'e']

Demo 3: adding a list and a string raises a TypeError.

>>> l = []
>>> l = l + 'table'
[...]
TypeError: can only concatenate list (not "str") to list

Not using += gives you the TypeError here because only __iadd__ implements the extending behavior.

Demo 4: common pitfall: += does not build a new list. We can confirm this by checking for equal object identities with the is operator.

>>> l = []
>>> l_ref = l # another name for l, no data is copied here
>>> l += [1, 2, 3] # uses __iadd__, mutates l in-place
>>> l is l_ref # confirm that l and l_ref are names for the same object
True
>>> l
[1, 2, 3]
>>> l_ref # mutations are seen across all names
[1, 2, 3]

However, the l = l + iterable syntax does build a new list.

>>> l = []
>>> l_ref = l # another name for l, no data is copied here
>>> l = l + [1, 2, 3] # uses __add__, builds new list and reassigns name l
>>> l is l_ref # confirm that l and l_ref are names for different objects
False
>>> l
[1, 2, 3]
>>> l_ref
[]

In some cases, this can produce subtle bugs, because += mutates the original list, while
l = l + iterable builds a new list and reassigns the name l.

BONUS

Ned Batchelder’s challenge to find this in the docs

Leave a Comment