Python 多重继承与 MRO
多重继承用 C3 线性化得到 MRO;super 沿 MRO 协作,混入(mixin)应保持正交。
#type / concept
#status / growing
#tech / dev
#resource / python
#tech / lang / python
[!info] 关联笔记
Python 多重继承与 MRO
这个概念为什么出现
日志混入、权限混入、序列化混入……多重继承能拼能力,但若查找顺序不明,会出现“调到了意料外的实现”。Python 用 C3 线性化生成 MRO(Method Resolution Order)。
[!abstract] 一句话理解 多基类时属性查找按
Cls.__mro__顺序;super()走向 MRO 中的下一个类,使混入可协作。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:API Handler 混入鉴权与审计
# mro_mixin_demo.py
# 业务意图:AuthMixin + AuditMixin 叠在 Handler 上。
# 教学点:
# - __mro__ 顺序;
# - super 协作链;
# - mixin 应调用 super。
class Handler:
def handle(self, req: str) -> str:
return f"handle:{req}"
class AuditMixin:
def handle(self, req: str) -> str:
return "audit|" + super().handle(req)
class AuthMixin:
def handle(self, req: str) -> str:
if not req.startswith("ok:"):
return "deny"
return "auth|" + super().handle(req)
class ApiHandler(AuthMixin, AuditMixin, Handler):
pass
def main() -> None:
print(ApiHandler.__mro__)
print(ApiHandler().handle("ok:pay"))
print(ApiHandler().handle("bad"))
if __name__ == "__main__":
main()
建议运行:
python mro_mixin_demo.py
期望输出(MRO 元组含类对象 repr):
(<class '__main__.ApiHandler'>, <class '__main__.AuthMixin'>, <class '__main__.AuditMixin'>, <class '__main__.Handler'>, <class 'object'>)
auth|audit|handle:ok:pay
deny
结合场景再看三个关注点
- 基类书写顺序影响 MRO:
AuthMixin在AuditMixin前。 - mixin 必须 super,否则链条断开。
- 鉴权失败直接返回,不再进入后续 handle。
核心概念与准确模型
- 查看:
Class.__mro__或Class.mro() - C3:既保持局部优先级又保持单调性
- 无法线性化时类创建失败
边界情况与反直觉行为
- 父类顺序冲突导致
TypeError: Cannot create a consistent method resolution order - 钻石继承靠 MRO 保证每个类最多出现一次协作路径
- mixin 带状态易变乱——优先无状态 mixin
常见误区
[!warning] 常见误区:多重继承是默认设计 错误理解:能力多就多继承。
正确模型:组合、协议、装饰器往往更清晰;mixin 要正交且文档化 MRO 预期。
工程实践
- 命名
XxxMixin - 只混入行为,不混入复杂构造参数
- 单测打印
__mro__锁定顺序
本节总结
MRO 是多重继承的地图;super 是沿地图前进的方式。先会读 __mro__,再写 mixin。
自测题
- 如何查看查找顺序?
- mixin 为什么要调用 super?
参考答案
Cls.__mro__。- 把控制权交给 MRO 下一类型,形成协作链。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| C3 method resolution | 历史文档 | C3 说明 |
| Data model – MRO | 规范 | 类型对象 |