The "augmented" assignment operators like +=
were introduced in Python 2.0, which was released in October 2000. The design and rationale are described in PEP 203. One of the declared goals of these operators was the support of in-place operations. Writing
a = [1, 2, 3]
a += [4, 5, 6]
is supposed to update the list a
in place. This matters if there are other references to the list a
, e.g. when a
was received as a function argument.
However, the operation can't always happen in place, since many Python types, including integers and strings, are immutable, so e.g. i += 1
for an integer i
can't possibly operate in place.
In summary, augmented assignment operators were supposed to work in place when possible, and create a new object otherwise. To facilitate these design goals, the expression x += y
was specified to behave as follows:
- If
x.__iadd__
is defined, x.__iadd__(y)
is evaluated.
- Otherwise, if
x.__add__
is implemented x.__add__(y)
is evaluated.
- Otherwise, if
y.__radd__
is implemented y.__radd__(x)
is evaluated.
- Otherwise raise an error.
The first result obtained by this process will be assigned back to x
(unless that result is the NotImplemented
singleton, in which case the lookup continues with the next step).
This process allows types that support in-place modification to implement __iadd__()
. Types that don't support in-place modification don't need to add any new magic methods, since Python will automatically fall back to essentially x = x + y
.
So let's finally come to your actual question – why you can add a tuple to a list with an augmented assignment operator. From memory, the history of this was roughly like this: The list.__iadd__()
method was implemented to simply call the already existing list.extend()
method in Python 2.0. When iterators were introduced in Python 2.1, the list.extend()
method was updated to accept arbitrary iterators. The end result of these changes was that my_list += my_tuple
worked starting from Python 2.1. The list.__add__()
method, however, was never supposed to support arbitrary iterators as the right-hand argument – this was considered inappropriate for a strongly typed language.
I personally think the implementation of augmented operators ended up being a bit too complex in Python. It has many surprising side effects, e.g. this code:
t = ([42], [43])
t[0] += [44]
The second line raises TypeError: 'tuple' object does not support item assignment
, but the operation is successfully performed anyway – t
will be ([42, 44], [43])
after executing the line that raises the error.