尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python中类的mro与继承关系详解
前言MRO 是 Method Resolution Order 的缩写中文常译作方法解析顺序。它回答一个问题当一个实例调用某个方法时Python 按什么顺序去各个类里找它单继承时这个问题看起来没什么可讲的——子类没有就往上找父类一条直线。但 Python 支持多重继承一个类可能有两条甚至更多路径通向同一个祖先这时往上找就不再是一条直线了。文档把这种结构称为菱形关系diamond relationship因为所有类最终都继承object任何多重继承都天然构成菱形。Python 的解法是C3 线性化把一个类及其所有祖先排成一个不重复的线性序列。围绕它常见的误解有两个以为多重继承的方法是深度优先、从左到右地全跑一遍。实际每个类只会被选中一次super()靠这个线性序列接力。以为 MRO 只看继承列表的书写顺序。实际上它还受每个基类自身的继承结构影响光看class D(B, C)猜不准。本文讲 C3 的规则、怎么查看 MRO以及它和super()的关系。一、MRO 要解决什么假设有这样一组类A/ \B C\ /DB和C都继承AD又同时继承B和C。如果按深度优先、从左到右去找方法先找D再找B再找B的父类A——可这时C还没被找过而A已经被找了两遍。谁先谁后、会不会重复就说不清了。文档对 Python 采用的算法的描述是它保持每个类声明时的从左到右顺序、每个父类只被访问一次、并且是单调的即一个类被继承后不会打乱已有父类的优先级。这套规则让多重继承的行为变得可预测。二、C3 线性化的结果长什么样先看最经典的菱形# 适用于 Python 3.8class A:passclass B(A):passclass C(A):passclass D(B, C):passprint([cls.__name__ for cls in D.__mro__])# [D, B, C, A, object]顺序是D → B → C → A → object。注意两点B和C谁在前面由class D(B, C)的书写顺序决定A排在两者之后而不是紧跟B——这正是线性化避免重复访问的手段。下表用查找某个方法时依次去哪些类找的角度列出几种继承结构的 MRO类定义MROclass B(A)B, A, objectclass C(A)C, A, objectclass D(B, C)D, B, C, A, objectclass E(C, B)E, C, B, A, objectclass F(D, E)冲突抛TypeError最后一行值得说明D要求B在C前E要求C在B前两者矛盾C3 无法给出一个一致序列于是 Python 直接报TypeError: Cannot create a consistent method resolution order (MRO)。三、查看 MRO__mro__ 与 mro()每个类都有__mro__属性它是一个元组列出方法解析时会依次检查的类# 适用于 Python 3.8class A:passclass B(A):passprint(B.__mro__)# (class __main__.B, class __main__.A, class object)类上还有mro()方法返回的是列表形式。文档说明mro()可以被元类重写用于自定义 MRO它在类创建时被调用结果存进__mro__。# 适用于 Python 3.8print(B.mro())# [class __main__.B, class __main__.A, class object]排查继承问题时第一件事就是打印类名.__mro__——它比任何推测都可靠。另外__bases__给出的是直接基类的元组__mro__才是完整链条两者别混用。四、MRO 与 super() 的配合这是 MRO 最实际的用途。super()返回一个代理对象从 MRO 中当前类之后的位置继续搜索。文档举的例子是如果__mro__是D - B - C - A - object而type是B那么super()会在C - A - object里找。# 适用于 Python 3.8class Base:def handle(self):return [Base]class AuthMixin:def handle(self):return [Auth] super().handle()class LogMixin:def handle(self):return [Log] super().handle()class API(AuthMixin, LogMixin, Base):passprint([c.__name__ for c in API.__mro__])# [API, AuthMixin, LogMixin, Base, object]print(API().handle())# [Auth, Log, Base]AuthMixin.handle里的super()跳到了LogMixin——这是它的MRO 后继不是它的父类AuthMixin的父类其实是object。这里就体现出 MRO 与super()是一体的不知道 MRO就预测不出super()会跳到哪。如果某个环节忘了写super()它后面的所有实现都会被静默跳过程序不报错# 适用于 Python 3.8class LogMixin:def handle(self):return [Log] # 没调 super()Base 永远轮不到五、MRO 冲突怎么排查出现Cannot create a consistent method resolution order (MRO)时说明继承结构本身矛盾典型是把祖先排在了后代后面# 适用于 Python 3.8class A:passclass B(A):pass# class C(A, B): # TypeError: Cannot create a consistent MRO# passB已经是A的子类class C(A, B)却要求A排在B前面这与A必须在B之后相矛盾。排查步骤建议固定成三条写出每个涉及类的__bases__画成图从上到下检查有没有祖先排在后代之后的写法试着删掉某个基类看是否是因为它把两条无关的链条强行合并导致矛盾。常见坑点1. 以为super()指的就是直接父类❌ 在多重继承里断言AuthMixin.handle里的super()会调到自己的父类。✅ 它调到的是当前实例的 MRO 中当前类之后的下一个类要打印__mro__才能确定。2. 用深度优先预测顺序❌ 以为D(B, C)会先把B的整条祖先链找完再找C。✅ C3 的输出是D, B, C, A, object——A被排到C之后。3. 在嵌套函数 / 生成器表达式里用零参super()❌ 以为super()在哪都能自动认出当前类和self于是在方法内部又套一层函数时照写super()。✅ 零参super()靠编译器在外围方法里填入当前类与第一个参数嵌套函数里不成立生成器表达式也会隐式生成嵌套函数这种场合要写显式两参形式super(当前类, self)。4. 以为继承列表相同MRO 就相同❌ 看到两个类都写成(X, Y)就断定它们的解析顺序完全一致。✅ 顺序还取决于X、Y各自继承了谁上游结构一变下游顺序可能跟着变必须打印__mro__才算数。5. 用__bases__当完整链条❌ 打印D.__bases__只看到(B, C)就以为这是全部顺序。✅__bases__是直接基类完整顺序看__mro__。6. MRO 冲突时反复调换顺序试错❌ 遇到TypeError就把继承列表换来换去直到不报错。✅ 冲突说明结构矛盾祖先排在了后代之后需要重新设计层次。7. 在子类里给__mro__赋值❌ 运行中直接SomeClass.__mro__ ...想强行改顺序。✅__mro__是只读的要自定义解析顺序只能在元类里重写mro()且在类创建前生效。8. 忘了每个类的 MRO 末尾都有object❌ 统计链长时漏算object或以为重写object的方法能救场。✅ 所有类的 MRO 都以object结尾多重继承里它只出现一次这也是任意多重继承都是菱形的原因。总结概念说明MRO属性/方法查找的顺序算法C3 线性化保持从左到右、每个类一次、单调查看方式类.__mro__元组、类.mro()列表super()从 MRO 中当前类之后继续搜索冲突表现TypeError: Cannot create a consistent MROMRO 不是一条只供阅读的规则它是super()行为的依据。想预测一段多重继承代码会调到哪个方法唯一可靠的办法就是打印__mro__再顺着序列看每个类的实现是不是都调了super()。把这两步养成习惯多重继承就不再是黑箱。
RELATED

相关推荐

DSC曲线分析全指南:从读图到热分析参数提取

DSC曲线分析全指南:从读图到热分析参数提取

1. DSC曲线分析到底在分析什么第一次拿到DSC曲线的人,十有八九会盯着那条忽上忽下的线发懵——横坐标是温度,纵坐标是热流率,曲线上冒出一个向下的峰,或者鼓起一个向上的包,然后呢?然后该看什么&#xff1f…

📅 2026/10/9 23:59:09
IIS7导出包真相:配置继承、内核参数与默认安全陷阱

IIS7导出包真相:配置继承、内核参数与默认安全陷阱

1. 这个“导出包”到底导出了什么?——IIS7默认配置的真相与误读很多人看到“IIS7默认配置及故障排除导出包”这个标题,第一反应是:这不就是个备份脚本或一键恢复工具吗?点几下鼠标,导出一个zip包,出问题了…

📅 2026/10/9 23:59:09
经济学思维实战课:用边际分析、机会成本与非价格配给解构真实生活

经济学思维实战课:用边际分析、机会成本与非价格配给解构真实生活

1. 这门课不是“背公式”,而是训练你识别生活里隐藏的交易逻辑“经济学基础(本)【4】”——光看标题,很多人第一反应是:又一门要划重点、背定义、算弹性系数的理论课。我带过三届本科经济学导论课,也帮某高…

📅 2026/10/9 23:59:09
MORE NEWS

更多资讯

📰

动作系统设计:从状态机到输入缓冲与命中判定的实践

上面这个东西当时做的时候,心里其实没底。动作系统不是单纯堆一堆动画切片让角色播片,真正麻烦的是"逻辑"。如果只是跑一个Demo,用状态机硬编码也没问题,做到十几个动作就要开始裂开;做到角色、敌人、场景交…

📰

深色模式实现全解析:CSS变量、三态逻辑与首屏防闪烁

1. 深色模式不只是换个背景色:从需求到技术选型的完整思考深色模式这个需求,最早是从用户反馈里冒出来的。当时后台数据显示,夜间时段用户停留时长明显低于日间,但访问量并不低。一开始我们以为是内容问题,后来做了几轮…

📰

Kali 安装 OpenClaw 完整指南:把 settings 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

游戏引擎渲染系统架构解析:从线程模型到渲染图

渲染系统大概是游戏引擎里最复杂的一块。它不只是把三角形画出来那么简单,还要考虑场景数据怎么流到 GPU、线程之间怎么协作、资源和内存怎么反复利用,以及渲染特性越来越多时怎么保持架构不崩。这篇作为系列第二篇,专门聊渲染系统架构。我会…

📰

智慧工厂落地指南:从56页PPT拆解设备层、数据层、应用层三层架构

简介:这份《智慧工厂解决方案》PPT面向制造业从业者、智能制造规划人员及数字化转型研究者,系统梳理了智能工厂从政策背景到落地实施的完整脉络。内容围绕《中国制造2025》与智能制造三步走目标展开,涵盖新兴技术推动、企业内在需求、智能制造…

📰

基于机器学习的遥感图像分类模型源码解析与实践指南

简介:这是一份基于机器学习的遥感图像分类模型源码包,面向计算机、人工智能、大数据等相关专业正在做课程设计、期末大作业或毕业设计的学生,也可供遥感图像与机器学习方向的学习者参考。包内共十三个文件,以六个Python源码脚本为…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬