3

I'm currently learning python operator overloading (__radd__ and __add__ to be exact) and I have the following code

class Commuter1:
    def __init__(self, val):
        self.val = val
    def __add__(self, other):
        print('add', self.val, other)
        return self.val + other


    def __radd__(self, other):
        print('radd', self.val, other)
        return other + self.val


x = Commuter1(88)
y = Commuter1(99)

print(x + y)

I have got the following result

enter image description here

When used separately, I understand how __radd__ and __add__ works. But for the line x + y, I'm not sure why both __radd__ and __add__ methods are evoked.

Thor
  • 9,638
  • 15
  • 62
  • 137
  • 6
    What do you think happens when you do `self.val + other`? – user2357112 Jul 12 '18 at 06:22
  • 1
    I think he answers your question already. – Marcus.Aurelianus Jul 12 '18 at 06:24
  • 1
    ah, i think i got it. Inside `__add__` function, the return statement `return self.val + other` invoke the `__radd__` function. The `other` in `return self.val + other` is passed to `__radd__` as the first argument (i.e. `other` in `return self.val + other` is assigned to the `self` in `def __radd__(self, other)`. And `self.val` in `return self.val + other` is assigned to the `other` argument in `def __radd__(self, other)`. I hope I have got this right – Thor Jul 12 '18 at 06:28

1 Answers1

10

First, Python looks at the types of x and y to decide whether to call x.__add__ or y.__radd__. Since they're both the same type Commuter1, it tries x.__add__ first.


Then, inside your __add__ method, you do this:

return self.val + other

So, Python looks at the types of self.val and other to decide whether to call self.val.__add__ or other.__radd__. Since they're unrelated types int and Commuter1, it tries int.__add__ first.

But int.__add__ returns NotImplemented for a type it doesn't know about, so Python falls back to calling other.__radd__.


Inside your __radd__ method, you do this:

return other + self.val

So, Python looks at the types of other and self.val to decide whether to call other.__add__ or self.val.__radd__. Since they both the same type int, it tries __add__ first.


And of course int.__add__ works on another int, so it returns a value for the inner + inside your __radd__, which you return, which returns a value for the + inside __add__, which you return, which returns a value for the top-level +, which you print.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • @Thor No problem; when you're trying to work out the complicated rules for whether it tries `__add__` or `__radd__` first, and what does and doesn't force a fallback, it can be very easy to lose sight of the simpler parts of what's happening… – abarnert Jul 12 '18 at 06:33
  • do you mind if I ask, how you learned all this? I want to know if I can take away anything from your learning experience so i can attempt to solve similar problem in the future by myself. – Thor Jul 12 '18 at 06:34
  • @Thor I might be a bit late, but looking at the official documentation from Python is a nice starter if you don't know where to search. Other than that, it's mostly experience and reading up on other people doing stuff. For this case, the documentation is found here: https://docs.python.org/3/reference/datamodel.html – mazunki Sep 08 '20 at 01:47