为何Python3.7与3.10中涉及int多继承的MRO及str()调用表现不同?
Python 3.7到3.10多继承中__str__方法查找行为变化的疑问
将代码库从Python 3.7.5升级至3.10/3.11时遇到异常:按多继承左到右的方法查找规则,3.7.5中继承顺序为[int, Base]的类会调用int的__str__方法,但3.10及3.11中该类会调用Base的__str__方法,__repr__方法则表现正常。是否存在认知遗漏或这是一个Bug?
测试代码
class Base: def __str__(self) -> str: return 'Base' def __repr__(self) -> str: return 'Base' class Integer(int, Base): def __new__(cls, value): return int.__new__(cls, value) class String(str, Base): def __new__(cls, value): return str.__new__(cls, value) print(f"str: {Integer(2)} and {String(2)}") print(f"repr: {repr(Integer(2))} and {repr(String(2))}")
版本输出
Python 3.7.5输出
str: 2 and 2 repr: 2 and '2'
Python 3.10及3.11输出
str: Base and 2 repr: 2 and '2'
原因说明
这不是Bug,是Python 3.9及以后版本对内置类型子类的特殊方法查找逻辑做了调整,让多继承场景下的方法查找更贴合MRO(方法解析顺序)规则:
- 在Python 3.7及更早版本中,对于
int这类内置数值类型的子类,只要子类没有显式重写__str__,解释器会直接调用内置类型的__str__实现,完全跳过MRO中的其他自定义父类。 - 从Python 3.9开始,这个逻辑被修正:解释器会严格按照MRO顺序查找特殊方法。你的
Integer类MRO是[Integer, int, Base, object],由于int的__str__是C层面实现的slot方法,解释器会继续往后查找MRO中的Base类,找到它的Python实现的__str__,因此调用了Base的方法。 - 而
String类的情况不同,str的__str__同样是slot方法,但它在MRO中的顺序比Base靠前,所以解释器会优先调用str的__str__,输出结果和3.7版本一致。
至于__repr__方法表现正常,是因为int和str的__repr__在MRO中优先级高于Base,且解释器对__repr__的处理逻辑在这次调整中未受影响,依然会优先调用内置类型的实现。
内容的提问来源于stack exchange,提问作者koltony
相关产品推荐
相关产品推荐

