# Is i = i + n truly the same as i += n?

One block of code works but the other does not. Which would make sense except the second block is the same as the first only with an operation written in shorthand. They are practically the same operation.

```    l = ['table']
i = []
```

### Version 1

```    for n in l:
i += n
print(i)
```

Output: `['t', 'a', 'b', 'l', 'e']`

### Version 2

```    for n in l:
i = i + n
print(i)
```

Output:

TypeError: can only concatenate list (not "str") to list

What is causing this strange error?

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

From: stackoverflow.com/q/52747784

Back to homepage or read more recommendations: