MadPhysicist
MadPhysicist

Reputation: 5831

Overriding Commutative Operations For Same Class Operands in Python

I am trying to understand how operator overriding works for two operands of a custom class.

For instance, suppose I have the following:

class Adder:
    def __init__(self, value=1):
        self.data = value
    def __add__(self,other):
        print('using __add__()')
        return self.data + other
    def __radd__(self,other):
        print('using __radd__()')
        return other + self.data

I initialize the following variables:

x = Adder(5)
y = Adder(4)

And then proceed to do the following operations:

1 + x
using __radd__()
Out[108]: 6

x + 2
using __add__()
Out[109]: 7

The two operations above seem straigtforward. If a member of my custom class is to the right of the "+" in the addition expression, then __radd__ is used. If it is on the left, then __add__ is used. This works for expressions when one operand is of the Adder type and another one is something else.

When I do this, however, I get the following result:

x + y
using __add__()
using __radd__()
Out[110]: 9

As you can see, if both operands are of the custom class, then both __add__ and __radd__ are called.

My question is how does Python unravel this situation and how is it able to call both the right-hand-addition function, as well as the left-hand-addition function.

Upvotes: 0

Views: 80

Answers (2)

Moses Koledoye
Moses Koledoye

Reputation: 78556

That's the because the implementation of your __add__ and __radd__ method do not give any special treatment to the instances of the Adder class. Therefore, each __add__ call leads to an integer plus Adder instance operation which further requires __radd__ due to the Adder instance on the right side.

You can resolve this by doing:

def __add__(self, other):
    print('using __add__()')
    if isinstance(other, Adder):
        other = other.data
    return self.data + other

def __radd__(self, other):
    print('using __radd__()')
    return self.__add__(other)

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599610

It's because inside your methods you add the data to other. This is itself an instance of Adder. So the logic goes:

  • call __add__ on x;
  • add x.data (an int) to y (an Adder instance)
  • ah, right-hand operand is an instance with a __radd__ method, so
  • call __radd__ on y;
  • add int to y.data (another int).

Usually you would check to see if other was an instance of your class, and if so add other.data rather than just other.

Upvotes: 1

Related Questions