Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python Advanced Objects Math

Flore W
Flore W
4,744 Points

What is the purpose of the __iadd__ magic method, since it works fine without it?

I know this question has been asked previously, but it didn't shatter my doubts: I get the exact same result in the console with or without the iadd method.

>>> five = Numstring(5)
>>> five += 1
>>> five
6

In which case would iadd add any value? Thanks!

Quinton Rivera
Quinton Rivera
5,177 Points

Why doesnt it work if we place the code from inside of iadd and place it inside of the add method? The only difference i see is that inside of the iadd method you assign the value so you can store it, does python not let you store inside of the add method, im sure why we couldnt add that type of functionality to the code.

4 Answers

Hello Flore Wang

So the main difference between __add__ and __iadd__ is that __iadd__ is actually storing that value its adding into the self.value.

Example: If this is my class.

class NumString:

    def __init__(self, value):
        self.value = str(value)

    def __int__(self):
        return int(self.value)

    def __str__(self):
        return self.value

    def __add__(self, other):
        return int(self) + other

    def __iadd__(self, other):
        self.value = self + other
        return self.value

Now if I did the following with my class.

some_num1 = NumString(0) # Create an instance of NumString with 0 as value.
str(some_num1) # Check what is contained within self.value in this instance.
# Output: '0'

some_num1 + 1 # We add some_num1 to 1, this returns back the calculation using the __add__ method
str(some_num1) # check what some_num1 is holding for a self.value
# Output: '0'

some_num1 += 2 # We in-place add some_num1 to 2, this stores and returns the new stored value using __iadd__ method.
str(some_num1) # check what some_num1 is holding now?
# Output: '2'

Can you see how __iadd__ is storing the calculated value self.value and the __add__ method is just calculating and returning it but NOT storing it.

Flore W
Flore W
4,744 Points

Hi Chris, thanks a lot! I tried deleting the line

    def __iadd__(self, other):
        self.value = self + other
        return self.value

and it returns exactly the same if I perform

>>>some_num = NumString(0)
>>>some_num +=2 
>>>str(some_num)
#returns '2'

How come?

Hey Flore Wang

This is because if you dont define, or even if you do define your own __iadd__() method. The __add__()method is called fro

So if you run this code. You will see

class NumString:

    def __init__(self, value):
        self.value = str(value)

    def __int__(self):
        return int(self.value)

    def __str__(self):
        return self.value

    def __add__(self, other):
        print('This is from __add__()')
        return int(self) + other

    def __iadd__(self, other):
        print('This came from __iadd__()')
        self.value = self + other
        return self.value

Once you define this you can run something like

ns1 = NumString(5)
ns1 += 1
# output: This came from __iadd__()
# output: This is from __add__()

Then if you remove that __iadd__ method, you will see that it still prints __add__ print statement because it still uses it as a fallback for +=

Flore W
Flore W
4,744 Points

Hey Chris, thanks again for the detailed explanation, I really like the fact that you have added "print('This is from add()')", it's super useful for debugging.

I have tried your code and I still get the same result with or without iadd.

So with iadd (exactly the code you posted above), I get:

>>> nb = NumString(0)
>>> nb += 1
This is from __iadd__()
This is from __add__()
>> print(nb)
1

And without iadd, I get:

>>> nb = NumString(0)
>>> nb += 1
This is from __add__()
>> print(nb)
1

The add method alone has stored my new value! I thought that was iadd's role?

Alternatively, when I delete add and only keep iadd, I get a TypeError.

>>> nb = NumString(0)
>>> nb += 1
This is from __iadd__()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/home/treehouse/workspace/numstring2.py", line 14, in __iadd__
       self.value = self + other
TypeError: unsupported operand type(s) for +=: "NumString" and "int"

I am confused as to iadd 's role. It seems that add can do pretty much everything that iadd has to do (storing the value), so why do we still need it?

Hi it does not make sense

Why

some_num + 1 

return zero in both cases with and without iadd

some_num += 1 

print 1 in both cases with and without i add

Akanksha Singh
Akanksha Singh
5,083 Points

As already discussed, we know that if iadd is not defined we go to add, the purpose of iadd is to assign a value to the instance itself, in case of +=, so if you change the functionality of iadd to something other than add, you will have the power to customize the +=.

Example :

class NumString:

  def __init__(self,value):
    self.value = str(value)

  def __str__(self):
    return self.value

  def __int__(self):
    return int(self.value)

  def __float__(self):
    return float(self.value)

  def __add__(self, other):
    if('.' in self.value):
      return float(self) + other
    return int(self) + other

  def __radd__(self, other):
    return self + other 

  def __iadd__(self,other):
    self.value = int(self.value) + 45 + other
    return self.value



four = NumString(4)
print ( str(four) + "hi")
print (type (int(four)))
print(type (float(four)))
two = 5 + four 
print(two) #prints 9
four += 1
print(four) #print 47

After Reading All The Comments . Your Comment Is To The Point

Yes, so the TypeError occurs at that point because Python doesnt know how to perform the operation between these type separate data types right? It has no way of knowing how to convert a NumString to an Int or an Int to a NumString to perform + on it. It just goes, "Uh oh I have no idea how to ADD a NumString to this Integer type. So best thing I can do is raise a TypeError

The logic that you wrote inside:

def __add__(self, other):
    # The logic in here told the object how to react to the thing it was getting + to.
    # without the logic for this method, Python doesnt know what to do when it encounters
    # NumType(0) + 10 because they are two different data types technically 
Sebastiaan van Vugt
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Sebastiaan van Vugt
Python Development Techdegree Graduate 13,554 Points

I see how iadd gets involved when "+=" is being used but like Flore W I still don't see the use. If you leave it out add will do the job anyway and iadd doesn't seem to be capable of doing anything without add. When would I therefore ever want to use iadd?

Responding to the reply below:

I guess what puzzled me most is trying to think of a situation when iadd would come in handy.

Hey Sebastiaan van Vugt

It isnt absolutely necessary to implement __iadd__

The += operator is shorthand.

The statement

nb += 1

is the same as saying

nb = nb + 1

So if you dont implement __iadd__ python will just fallback on the __add__ method. But if you do implement the __iadd__ method Python will attempt to use it.

Hi. I read the above dialogue and have this question. Can you use += on integers without implementing iadd , say for example, by instantiating NumString? Thanks