DEV Community

Tahmid Hossain
Tahmid Hossain

Posted on • Edited on

a += b is not the same as a = a + b

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]
Enter fullscreen mode Exit fullscreen mode
>>> a = [1, 2, 3]
>>> b = a
>>> a = a + [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Now, run the below code:

a = MyList ([1, 2, 3])
b = a
a = a + b
Enter fullscreen mode Exit fullscreen mode

It gives following output:

__add__ has been called
Enter fullscreen mode Exit fullscreen mode

Now, run the below code:

a = MyList ([1, 2, 3])
b = a
a += b
Enter fullscreen mode Exit fullscreen mode

It gives the following output:

__iadd__ has been called
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

It gives following output:

__iter__ has been called
Enter fullscreen mode Exit fullscreen mode

So, for types that support both __add__ and __iadd__ you therefore have to be careful which one you use.

Top comments (2)

Collapse
 
paddy3118 profile image
Paddy3118

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.

Collapse
 
tahmid02016 profile image
Tahmid Hossain

Ahh... My mistake...
Thanks for commenting...