Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I overload operators so that type on the left/right does not matter?

A simple example - I want to have a point class that describes a point in 2 dimensions. And I want to be able to add two points together... as well as multiply two points together (don't ask me why), or multiply a point by a scalar. For right now, I'll only implement it as if the scalar is an integer but fraction or floats is also trivial to do.

class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0},{1})".format(self.x, self.y)

    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Point(x, y)

    def __mul__(self, other):
        if isinstance(other, Point):
            x = self.x * other.x
            y = self.y * other.y
            return Point(x, y)
        elif isinstance(other, int):
            x = self.x * other
            y = self.y * other
            return Point(x, y)

So, this works when I perform:

>>> p1 = Point(2, 3)
>>> p2 = Point(-1, 2)
>>> print(p1*p2)
(-2,6)
>>>print(p1*4)
(8,12)

but it does NOT work when I reverse the order of scalar and Point object:

>>>print(4*p1)
Traceback (most recent call last):   
  File "<input>", line 1, in <module> TypeError: unsupported operand type(s) for *:
'int' and 'Point'

How can I write the code where it doesn't matter if I write '4 * p1' or 'p1 * 4' that I'll still execute the same code and return the same answer? Do I accomplish this by overloading the mul operator for int objects or is there another way?

Note: code for my short example was borrowed from https://www.programiz.com/python-programming/operator-overloading

like image 940
boymeetscode Avatar asked Jan 12 '18 01:01

boymeetscode


People also ask

What is the correct way to overload operator?

In case of operator overloading all parameters must be of the different type than the class or struct that declares the operator. Method overloading is used to create several methods with the same name that performs similar tasks on similar data types.

Can left shift operator be overloaded?

you can't overload left shift operator like this in c#. Because in the left shift operator, the first operand must be the containing type and second operand must be an integer.

How do you overload left shift operator Python?

Python Bitwise Left-Shift Operator Overloading For the left-shift operator, the magic method is the __lshift__(self, other) method. It should return a new custom object that is the result of the bitwise operation.

Which of the operators Cannot be overload?

You cannot overload the following operators: . You cannot overload the preprocessor symbols # and ## . An operator function can be either a nonstatic member function, or a nonmember function with at least one parameter that has class, reference to class, enumeration, or reference to enumeration type.


1 Answers

(As I was about to submit the question, I was tagging, and found the answer. I think it is worthwhile to document it here so others can easily find it.)

Define __rmul__(self, other). This stands for right-multiply. When the object on the left fails to multiply (in the example above the integer doesn't know how to multiply the Point class on the right) Python will look at the object on the right to see if the __rmul__(self, other) special method is defined, and does it work? If it does, it will use this implementation instead.

For classes that are commutative (i.e. you can multiply either AB or BA and get the same results) you can define it as:

def __mul__(self, other):
    if isinstance(other, Point):
        x = self.x * other.x
        y = self.y * other.y
        return Point(x, y)
    elif isinstance(other, int):
        x = self.x * other
        y = self.y * other
        return Point(x, y)

def __rmul__(self, other):
    return self.__mul__(other)
like image 146
boymeetscode Avatar answered Nov 10 '22 15:11

boymeetscode