基本示例。你自己写
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))
但是
整数
不知道如何处理
FooInt公司
,和返回
NotImplemented
;它不知道
intvalue
具有可用于此目的的价值。在这一点上,Python不能仅仅调用
FooInt.__sub__(FooInt(456), 123)
因为它不能假设减法是可交换的(事实上,就像在大多数数值系统中一样,在这种情况下,减法是不可交换的,你不能只交换算子的左右两边就得到正确的结果)。这就是为什么
__rsub__
存在;它允许您检查另一个类是否有处理操作的方法,同时告诉它两件事:
-
它位于二进制运算符的右侧(允许它正确处理交换性)
-
左边的项目不知道如何处理操作,所以这是最后一次纠正错误的机会
第二点也非常重要。实施时
__xxx__
(左手操作符)你想在你识别的类型上非常保守。如果你不知道你正在使用一个已知的正确处理程序处理一个已知具体类型,那么你不应该试图处理未知类型;另一个类型可能知道如何正确执行操作,因此您返回
未实现
让另一方来处理
__rxxx__
,你是最后的机会;另一个人不知道该怎么办,所以你应该对你接受的事情持自由态度,如果你有任何方法来处理它,就尽你所能。你可以在上的Python文档中看到这一点
Implementing the arithmetic operations
;这个
__xxx__
混凝土类型的操作检查(
Fraction
,它检查
小部分
,
整数
,
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
;假设子类将有更多的信息来正确地确定要做什么,所以它首先尝试执行操作。