如何重载运算符以使左/右类型无关紧要?

时间:2018-01-12 01:07:41

标签: python operator-overloading

一个简单的例子 - 我想要一个描述2维点的点类。我希望能够将两个点加在一起......以及将两个点相乘(不要问我为什么),或者将一个点乘以标量。就目前而言,我只会实现它,好像标量是一个整数,但是分数或浮点数也是微不足道的。

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)

所以,这在我执行时有效:

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

但是当我颠倒标量和Point对象的顺序时它不起作用:

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

如果我写下4 * p1&#39;那么如何编写代码并不重要?或者&#39; p1 * 4&#39;我还会执行相同的代码并返回相同的答案吗?我是通过为int对象重载 mul 运算符来完成此操作还是有其他方法?

注意:我的简短示例的代码是从https://www.programiz.com/python-programming/operator-overloading

借来的

1 个答案:

答案 0 :(得分:3)

(当我准备提交问题时,我正在标记,并找到答案。我认为在此处记录它是值得的,以便其他人可以轻松找到它。)

定义__rmul__(self, other)。这代表右乘。当左边的对象无法相乘时(在上面的例子中,整数不知道如何将右边的Point类相乘),Python会查看右边的对象,看看是否__rmul__(self, other)定义了特殊方法,它是否有效?如果是,它将使用此实现。

对于可交换的类(即您可以将A B或B A相乘并得到相同的结果),您可以将其定义为:

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)