In python a += b
is not equivalent as a = a + b
. They do not behave the same always. Consider the following:
>>> a = [1, 2, 3]
>>> b = a
>>> a += [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]
>>> a = [1, 2, 3]
>>> b = a
>>> a = a + [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3]
What happend here:
-
a += b
modified the list in-place. That means it extended a such that a and b had reference to the same list. -
a = a + b
expression created a new list and changed a 's reference to that new list. And b refered to the old list. Why it happened? Here comes how python implements+
and+=
operators. When you use+
operator python calls the__add__
special method. On the other hand+=
operator calls the__iadd__
special method, and if__iadd__
is not available only then it uses__add__
method. See below:
class MyList (list):
def __add__ (self, other):
print ("__add__ has been called")
return super (MyList, self).__add__ (other)
def __iadd__ (self, other):
print ("__iadd__ has been called")
return super (MyList, self).__iadd__ (other)
Now, run the below code:
a = MyList ([1, 2, 3])
b = a
a = a + b
It gives following output:
__add__ has been called
Now, run the below code:
a = MyList ([1, 2, 3])
b = a
a += b
It gives the following output:
__iadd__ has been called
The __iadd__
special method is for an inplace addition. That is it mutates the object that it acts on (in a += b
__iadd__
mutates a). On the other hand,__add__
method returns a new object (in a = a + b
we assigned __add__
's returned object into a).
__iadd__
is only available for mutable types. That's why for immutable types like integers (int
), strings (str
) and tuple
both +
and +=
are equivalent as they both calles __add__
. And this is what lets you use +=
on immutable types.
Now, let's see another difference between +
and +=
. Consider the following:
>>> a = [1, 2, 3]
>>> b = "hello"
>>> a + b
TypeError: can only concatenate list (not "str") to list
>>> a += b
>>> a
[1, 2, 3, 'h', 'e', 'l', 'l', 'o']
Here a + b
gives TypeError
. Because +
operator is symmetrical. So, we can't add a list
and str
. But +=
operator is obviously not symmetrical. It is equivalent to list.extend
, which iterates over the second operand. See below:
class MyStr (str):
def __iter__ (self):
print ("__iter__ has been called")
return super (MyStr, self).__iter__()
a = [1, 2, 3]
b = "hello"
a += b
It gives following output:
__iter__ has been called
So, for types that support both __add__
and __iadd__
you therefore have to be careful which one you use.
Top comments (2)
a = [1, 2, 3]
b = a
b = a + [4, 5, 6]
print('a', a) # [1, 2, 3]
print('b', b) # [1, 2, 3, 4, 5, 6]
The output for your code is nor what you stated in your second code block - you swap the a and b outputs.
Ahh... My mistake...
Thanks for commenting...