基本示例。你写你自己的int
般类:
class FooInt:
... other stuff elided ...
def __sub__(self, other):
if isinstance(other, FooInt):
return self.__class__(self.intvalue - other.intvalue)
elif isinstance(other, int):
return self.__class__(self.intvalue - other)
else:
return NotImplemented
现在你有一些代码的作用:
FooInt(123) - 456
也能正常工作; Python在左侧看到FooInt
,看到它有__sub__
,并且调用FooInt.__sub__(FooInt(123), 456)
,它返回时没有错误,我们很好。
接下来,我们看到:
123 - FooInt(456)
的Python试图调用int.__sub__(123, FooInt(456))
,但int
不知道如何处理FooInt
,并返回NotImplemented
;它不知道intvalue
有一个它可以用于这个目的的价值。在这一点上,Python不能仅仅调用FooInt.__sub__(FooInt(456), 123)
,因为它不能假设减法是可交换的(事实上,在大多数数值系统中,在这种情况下,减法是不可交换的,所以不能只交换右侧和左侧的操作员并获得正确的结果)。这就是为什么__rsub__
存在;它可以让你检查其它类的处理操作的装置,同时告诉它两件事情:
- 这是对二元运算符的右侧(允许它正确处理可交换)
- 该项目上左侧不知道如何处理手术,所以这是最后一次正确的手术。
第二点也很重要。在执行__xxx__
(左侧操作符)时,您希望对所识别的类型非常保守。如果你不知道你正在使用一个已知正确的处理程序的已知具体类型,你不应该尝试处理未知的类型;另一种类型可能知道如何正确操作,因此您返回NotImplemented
并让对方处理它。当你实施__rxxx__
时,你是最后的机会;另一个人不知道该怎么做,所以如果你有任何处理它的方法,你应该对自己接受的事情保持自由,并尽力做到最好。您可以在Implementing the arithmetic operations上的Python文档中看到此操作;所述__xxx__
操作检查混凝土类型(Fraction
,它检查Fraction
,int
,float
,和complex
),而运营商__rxxx__
检查一般接口(numbers.Integral
,numbers.Rational
,numbers.Real
等)。
我已经掩盖了一个比较重要的观点:If the class on the right side is a subclass of the class on the left, it has its reflected __rxxx__
method called first;假定是子类将有更多的信息来正确地确定要做什么,所以它给予了执行操作的第一步。
例如你想为你的类型实现一个'-'来处理整数,并且你希望它能够工作,无论int是在左边还是右边,并且你不能改变'-'实现的int –