【问题标题】:Changing the order of operation for __add__, __mul__, etc. methods in a custom class更改自定义类中 __add__、__mul__ 等方法的操作顺序
【发布时间】:2016-04-21 23:53:01
【问题描述】:

我有一个向量类:

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的父级)类中定义它?

【问题讨论】:

标签: python class object operator-overloading


【解决方案1】:

你还需要定义__radd__

有些操作不一定像 a + b == b + a 这样计算,这就是 Python 定义 addradd 方法的原因。

更好地解释自己:它支持“int”没有定义+ 操作和class Vector 实例作为操作的一部分的事实。所以vector + 1和1 + vector是不一样的。

当 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)

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

【讨论】:

  • 这里可能需要更多解释?
  • __mul____div__ 等是否类似?所以__rmul____rdiv__等等?
  • 是的,如果操作中的第一个对象(一切都是对象)不支持与第二个对象的操作
  • 好答案,我接受这个答案主要是因为提示__radd__=__add__,我喜欢单线解决方案:)
  • 在您的情况下,这是解决方案;)
【解决方案2】:

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

因此,您只需在 Vector 类中定义 __radd__() 方法,1 + y 就会按您的预期工作。

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

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

更新: 根据您的用例,您可能还希望实现 __iadd__() 方法(及其近亲)来覆盖 += 运算符。

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

【讨论】:

    猜你喜欢
    • 2021-11-19
    • 1970-01-01
    • 2014-09-13
    • 2011-10-31
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    相关资源
    最近更新 更多