Why does b+=(4,) work and b = b + (4,) doesn't work when b is a list?
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
.
They are not equivalent:
b += (4,)
is shorthand for:
b.extend((4,))
while +
concatenates lists, so by:
b = b + (4,)
you're trying to concatenate a tuple to a list
When you do this:
b += (4,)
is converted to this:
b.__iadd__((4,))
Under the hood it calls b.extend((4,))
, extend
accepts an iterator and this why this also work:
b = [1,2,3]b += range(2) # prints [1, 2, 3, 0, 1]
but when you do this:
b = b + (4,)
is converted to this:
b = b.__add__((4,))
accept only list object.