Python Fraction 子类如何让运算返回子类实例?
数据小陈
结论
这是 Fraction 当前实现的行为。继承不会让父类的算术方法自动返回子类实例。要让 F + F 返回 F,需要在子类中重载相应运算符,并将父类的运算结果转换为子类。每种运算符都要单独处理,没有通用开关可以自动改变所有继承方法的返回类型。
为什么会返回 Fraction
示例中的 x 和 y 都是 F,但 x + y 调用的是继承来的加法实现。这个实现返回 Fraction,即使 self 是 F,结果也不会自动转换为 F。
重载运算符
可以先为加法添加子类实现:
from fractions import Fraction
class F(Fraction):
def __add__(self, other):
result = super().__add__(other)
if result is NotImplemented:
return NotImplemented
return type(self)(result)
def __radd__(self, other):
result = super().__radd__(other)
if result is NotImplemented:
return NotImplemented
return type(self)(result)
__add__ 处理 F 实例作为左操作数的加法,__radd__ 处理 Python 调用反向加法方法的情况。保留 NotImplemented 很重要:如果父类不支持某个操作数,应让 Python 按二元运算规则继续尝试,不要把 NotImplemented 当作可构造的结果。
这段代码只处理加法。若要让其他运算也返回 F,还需按需实现对应方法,例如减法、乘法、除法及其反向运算。不同运算的返回值未必都是数值实例:比较通常返回布尔值,整除等操作也可能返回整数。是否转换结果,应根据每种运算的语义决定。
使用时的注意点
type(self)(result)假设子类构造函数能接受父类返回的结果。如果子类增加了必填参数或改变了构造规则,就需要相应调整转换逻辑。- 混用
F、Fraction和其他数值类型时,结果类型取决于参与运算的类型及其运算方法。需要逐一确认要支持的操作数组合。 - 如果需要大量自定义运算符,也可以考虑组合或包装
Fraction,但所需的数值接口需要自行提供。
备注:内容仅供参考。
