1

Asking just out of curiocity. I've been playing around with python, and noticed this behaviour:

  1. (2).__add__(2) results in 4, which is totally expected;
  2. (2).__add__('a') results in NotImplemented - nothing weird yet;
  3. 'a'.__add__(2) produces an exception.

But, when trying to create my own class like so:

class Integer:
    def __init__(self, d):
        self.val = d
    def __add__(self, i):
        return self.val+int(i)
    def __iadd__(self, i):
        self.val += int(i)
        return self
    def __int__(self):
        return self.val

and comparing it to decimal.Decimal, some weird stuff happens. They behave similarly in this case:

import decimal

a = Integer(2)
a += 2
print(int(a+2))

d = decimal.Decimal(2)
d += 2
print(int(d+2))

However, this is not as similar: 2+d works normally while 2+a throws an exception:

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    2+a
TypeError: unsupported operand type(s) for +: 'int' and 'Integer'

even though (2).__add__(a) and (2).__add__(d) both produce NotImplemented and a.__add__(2) and d.__add__(2) work normally. What exactly is happening with decimal.Decimal and how can I make this happen with my class?

3
  • throws an exception can you please paste it here? Commented May 13, 2020 at 13:45
  • @Tgsmith61591 sure Commented May 13, 2020 at 13:46
  • 1
    That's why __radd__ exists Commented May 13, 2020 at 13:48

1 Answer 1

2

Implement __radd__ too:

class Integer:
    def __init__(self, d):
        self.val = d

    def __add__(self, i):
        return self.val + int(i)

    def __radd__(self, i):
        return self.__add__(i)  # might be different if operation is not commutative

    def __iadd__(self, i):
        self.val += int(i)
        return self

    def __int__(self):
        return self.val


x = Integer(5) + 5
y = 5 + Integer(5)
Sign up to request clarification or add additional context in comments.

4 Comments

How exactly does that work? Is __radd__ called only after __add__ returns NotImplemented? Are there any special cases ( __radd__ returns NotImplemented or something) and, if there are, what would happen in those?
Why isn't __radd__ documented inside operator module?
Re your first question: yes, it looks like reverse functions are called if the forward functions raise NotImplemented: github.com/python/cpython/blob/…
Re your second question: because it doesn't need to have a mapping for an operator function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.