Is i = i + n truly the same as i += n?
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, whilel = l + iterable
builds a new list and reassigns the name l
.
BONUS
Ned Batchelder's challenge to find this in the docs
If in the second case, you wrap a list around n
to avoid errors:
for n in l:
i = i + [n]
print(i)
you get
['table']
So they are different operations.
No.
7.2.1. Augmented assignment statements:
An augmented assignment expression like
x += 1
can be rewritten asx = x + 1
to achieve a similar, but not exactly equal effect. In the augmented version, x is only evaluated once. Also, when possible, the actual operation is performed in-place, meaning that rather than creating a new object and assigning that to the target, the old object is modified instead.