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 += bmodified the list in-place. That means it extended a such that a and b had reference to the same list. -
a = a + bexpression 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...