The problem with “why” questions is that usually they can mean multiple different things. I will try to answer each one I think you might have in mind.
“Why is it possible for it to work differently?” which is answered by e.g. this. Basically, +=
tries to use different methods of the object: __iadd__
(which is only checked on the left-hand side), vs __add__
and __radd__
(“reverse add”, checked on the right-hand side if the left-hand side doesn’t have __add__
) for +
.
“What exactly does each version do?” In short, the list.__iadd__
method does the same thing as list.extend
(but because of the language design, there is still an assignment back).
This also means for example that
>>> a = [1,2,3]
>>> b = a
>>> a += [4] # uses the .extend logic, so it is still the same object
>>> b # therefore a and b are still the same list, and b has the `4` added
[1, 2, 3, 4]
>>> b = b + [5] # makes a new list and assigns back to b
>>> a # so now a is a separate list and does not have the `5`
[1, 2, 3, 4]
+
, of course, creates a new object, but explicitly requires another list instead of trying to pull elements out of a different sequence.
“Why is it useful for += to do this? It’s more efficient; the extend
method doesn’t have to create a new object. Of course, this has some surprising effects sometimes (like above), and generally Python is not really about efficiency, but these decisions were made a long time ago.
“What is the reason not to allow adding lists and tuples with +?” See here (thanks, @splash58); one idea is that (tuple + list) should produce the same type as (list + tuple), and it’s not clear which type the result should be. +=
doesn’t have this problem, because a += b
obviously should not change the type of a
.