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

Python继承int调换父类顺序时MRO解析__str__/__repr__异常问题

问题原因

这个现象没有违反MRO规则,核心原因是C实现的内置类型int没有在Python类层面定义__str__方法:

  • int的字符串转换逻辑是直接写在C层的tp_str类型槽位中的,没有映射为Python类属性字典里可被MRO检索到的__str__方法。
  • 而__repr__不同,int的__repr__是明确暴露在Python类层面的方法,会被MRO正常检索。

当定义class MyValue(int, Repr)时,MRO顺序为MyValue -> int -> Repr -> object,方法查找逻辑如下:

  • 调用__repr__时:MRO检索到int自带的__repr__方法,直接调用,不会走到Repr的实现,符合预期。
  • 调用__str__时:先查MyValue自身,无对应方法;再查int的类属性,找不到__str__;继续检索下一个父类Repr,发现Repr实现了__str__,就直接调用该版本,因此输出了自定义格式的字符串。

补充说明:单继承int时str()能正常返回数字字符串,是因为整条MRO链都找不到Python层面的__str__时,Python会回退调用C层的tp_str槽位逻辑;但只要MRO链上任意一个类定义了__str__,就会优先调用这个Python方法,不会触发C层回退。

修复方案

根据使用场景,可以选以下任意一种方案:

方案1:给int补全Python层面的__str__方法(最便捷)

int的__str__返回结果和__repr__完全一致,只需要在代码初始化阶段给int补上类属性,就能让MRO正常检索到int的字符串方法,行为和__repr__完全对齐:

# 代码最开头执行一次即可,无侵入性副作用
int.__str__ = int.__repr__

补全之后,不管父类顺序怎么写,MRO都会严格按照从左到右的优先级匹配方法,和最初的预期完全一致。

方案2:显式指定子类的方法绑定(无内置类型修改)

如果不想修改内置类型,可以在定义子类时显式声明__str__的绑定关系,不依赖MRO的隐式查找:

class MyValue(int, Repr):
    # 显式指定用int的字符串逻辑,和__repr__行为一致
    __str__ = int.__repr__

缺点是每个需要int优先级的子类都要单独写这一行。

方案3:修改Repr类兼容内置类型的特殊查找逻辑

如果既不想修改内置类型,也不想每个子类重复声明,可以修改Repr类的__str__逻辑,主动判断MRO链上排在自身前面的类,优先使用前置父类的字符串逻辑:

import numbers

class Repr:
    def __str__(self):
        # 找到Repr在MRO中的位置,遍历所有前置父类
        mro = self.__class__.__mro__
        repr_idx = mro.index(Repr)
        for cls in mro[:repr_idx]:
            # 如果前置父类是整数类型,直接返回原始数值的字符串表示
            if issubclass(cls, numbers.Integral):
                return cls.__repr__(self)
        # 前置父类无数值类型时,走自定义格式化逻辑
        # 这里替换成你实际的千万亿/亿亿量级格式化逻辑
        return '123.456qa'
   
    def __repr__(self):
        # 用super()替代手动遍历MRO,更符合Python继承规范
        return f'{self.__class__.__name__}({super().__repr__()})'

内容的提问来源于stack exchange,提问作者bm13kk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:30:18