You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

继承fractions.Fraction时子类运算符返回父类对象的问题

继承fractions.Fraction时运算符返回父类对象的解决方案与OOP原则探讨

当继承Python的fractions.Fraction类时,子类的数学运算符会返回父类Fraction对象而非子类对象,导致无法保留子类的自定义行为。例如:

from fractions import Fraction

class OtherFraction(Fraction):
    def __repr__(self):
        return f'OtherFraction({self.numerator}, {self.denominator})'

a = OtherFraction(1, 2)
b = OtherFraction(1, 3)
c = a + b
print(repr(a), repr(b), repr(c))

运行输出:

OtherFraction(1, 2) OtherFraction(1, 3) Fraction(5, 6)

无需重写所有运算符的解决方法

不用逐个手动重写运算符方法,可以通过动态生成运算符方法的方式批量处理:

from fractions import Fraction

class OtherFraction(Fraction):
    def __repr__(self):
        return f'OtherFraction({self.numerator}, {self.denominator})'

# 定义需要处理的算术运算符列表
operator_names = [
    '__add__', '__sub__', '__mul__', '__truediv__',
    '__floordiv__', '__mod__', '__pow__',
    '__radd__', '__rsub__', '__rmul__', '__rtruediv__',
    '__rfloordiv__', '__rmod__', '__rpow__'
]

def wrap_operator(original_method):
    def wrapped(self, other):
        # 调用父类的运算符方法得到结果
        result = original_method(self, other)
        # 如果结果是Fraction实例,转换为子类实例返回
        if isinstance(result, Fraction):
            return OtherFraction(result.numerator, result.denominator)
        return result
    return wrapped

# 批量为子类绑定包装后的运算符方法
for name in operator_names:
    original = getattr(Fraction, name)
    setattr(OtherFraction, name, wrap_operator(original))

测试后,a + b会返回OtherFraction(5, 6),符合预期。这种方式通过包装父类的运算符方法,自动将返回的Fraction实例转换为子类实例,避免了重复代码。

是否违背面向对象编程原则

这种期望子类运算符返回子类对象的想法不违背OOP原则:

  • 符合协变返回类型的设计思路:子类方法返回子类实例,仍然满足父类方法的返回类型约定(子类是父类的子类型,子类实例可以被安全地当作父类实例使用)。
  • 符合里氏替换原则:子类实例可以替换父类实例参与运算,同时保留自身的自定义行为,不会破坏原有代码的正确性。
  • 实际场景中,当子类扩展了父类的行为(比如自定义__repr__、额外属性或方法),要求运算结果保持子类类型是合理需求,能确保子类的特性被保留。

需要注意:如果子类添加了父类没有的额外属性,直接转换时需要确保这些属性被正确传递,否则会导致属性丢失。但在仅重写方法(如示例中的__repr__)的场景下,这种方法完全适用。

内容的提问来源于stack exchange,提问作者Saul Axel Martinez Ortiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:01:42