更改自定义类中__add __,__ mul__等方法的操作顺序

时间:2016-01-16 12:48:14

标签: python class object operator-overloading

我有一个矢量类:

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)

工作正常,即我可以写:

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

但是,如果操作顺序颠倒,则失败:

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

我理解错误:int对象添加到Vector对象是未定义的,因为我没有在int类中定义它。有没有办法解决这个问题而不在int(或int的父级)中定义它?

2 个答案:

答案 0 :(得分:7)

您还需要定义__radd__

某些操作不一定像这样评估a + b == b + a,这就是Python定义添加 radd 方法的原因。

更好地解释自己:它支持这样一个事实:“int”没有定义+操作,class Vector实例作为操作的一部分。因此,向量+ 1与1 +向量不同。

当Python试图查看1.__add__方法可以做什么时,会引发异常。 Python继续寻找Vector.__radd__操作来尝试完成它。

在OP的情况下,评估为 true ,并且足以__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)

哪个输出:

(2,3)

这同样适用于所有类似数字的操作。

答案 1 :(得分:4)

当您说x + y时,Python会调用x.__add__(y)。如果x未实现__add__(或该方法返回NotImplemented),则Python会尝试将y.__radd__(x)作为后备调用。

因此,您所要做的就是在Vector类中定义__radd__()方法,1 + y将按预期工作。

注意:您也必须对其他操作执行类似操作,例如:实施__mul__()__rmul__()对等

您可能还想查看this question,它会更详细地解释相同的原则。

<强>更新 根据您的使用情况,您可能还希望实施__iadd__()方法(及其表兄弟)来覆盖+=运算符。

例如,如果您在此处说y += 1yVector的实例),您可能希望修改y实例本身,而不是返回结果是新的Vector实例,这是您__add__()方法当前所做的事情。