Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing the order of operation for __add__, __mul__, etc. methods in a custom class

I have a vector class:

class Vector:
    def __init__(self, x, y):
        self.x, self.y = x, y
    def __str__(self):
        return '(%s,%s)' % (self.x, self.y)
    def __add__(self, n):
        if isinstance(n, (int, long, float)):
            return Vector(self.x+n, self.y+n)
        elif isinstance(n, Vector):
            return Vector(self.x+n.x, self.y+n.y)

which works fine, i.e. I can write:

a = Vector(1,2)
print(a + 1) # prints (2,3)

However if the order of operation is reversed, then it fails:

a = Vector(1,2)
print(1 + a) # raises TypeError: unsupported operand type(s)
             #                   for +: 'int' and 'instance'

I understand the error: the addition of an int object to an Vector object is undefined because I haven't defined it in the int class. Is there a way to work around this without defining it in the int (or parent of int) class?

like image 216
nluigi Avatar asked Jan 16 '16 12:01

nluigi


People also ask

What does the __ Add__ method do?

The __add__ method is used to implement addition operation. In Python, numbers are not primitive literals but objects. The num + 4 expression is equivalent to num. __add__(4) .

What is __ MUL __ in Python?

The Python __mul__() method is called to implement the arithmetic multiplication operation * . For example to evaluate the expression x * y , Python attempts to call x. __mul__(y) .

How do you add a method to a class in Python?

The normal way to add functionality (methods) to a class in Python is to define functions in the class body. There are many other ways to accomplish this that can be useful in different situations. The method can also be defined outside the scope of the class.


1 Answers

You need to also define __radd__

Some operations do not necessarily evaluate like this a + b == b + a and that's why Python defines the add and radd methods.

Explaining myself better: it supports the fact that "int" does not define a + operation with class Vector instances as part of the operation. Therefore vector + 1 is not the same as 1 + vector.

When Python tries to see what the 1.__add__ method can do, an exception is raised. And Python goes and looks for Vector.__radd__ operation to try to complete it.

In the OP's case the evaluation is true and suffices with __radd__ = __add__

class Vector(object):

    def __init__(self, x, y):
        self.x, self.y = x, y

    def __str__(self):
        return '(%s,%s)' % (self.x, self.y)

    def __add__(self, n):
        if isinstance(n, (int, long, float)):
            return Vector(self.x+n, self.y+n)
        elif isinstance(n, Vector):
            return Vector(self.x+n.x, self.y+n.y)

    __radd__ = __add__


a = Vector(1, 2)
print(1 + a)

Which outputs:

(2,3)

The same applies to all number-like operations.

like image 168
mementum Avatar answered Oct 23 '22 14:10

mementum