Python 的 __mro__ 解析

Python 的 __mro__(方法解析顺序)是一个关键概念,它决定了 Python 在继承层次结构中如何查找方法。让我们深入了解它是什么,为什么我们需要它,并观察它的实际应用。

🔍 什么是 mro

__mro__ 是一个元组,定义了 Python 在类层次结构中查找方法和属性的顺序。每个类都有这个属性,显示其线性化的继承路径。

class Animal:
    pass

class Dog(Animal):
    pass

print(Dog.__mro__)
# (<class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>)

Python 从左到右搜索:首先在 Dog 中,然后在 Animal 中,最后在 object 中。


🎯 我们为什么需要它?

MRO 解决了多重继承中的 钻石问题——当一个类从多个共享共同祖先的类继承时。

class A:
    def method(self):
        return "A"

class B(A):
    def method(self):
        return "B"

class C(A):
    def method(self):
        return "C"

class D(B, C):  # 菱形继承
    pass

d = D()
print(d.method())  # "B" - 遵循方法解析顺序
print(D.__mro__)

# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

没有方法解析顺序(MRO),Python 不知道是调用 B.method() 还是 C.method()。MRO 提供了一种一致、可预测的顺序,使用C3线性化算法


💡 实际使用案例

1. 协作继承中的 super()

super() 遵循 MRO,而不仅仅是父类。这使得协作多重继承成为可能:

class Logger:
    def save(self):
        print("记录日志...")
        super().save()  # 继续 MRO 链

class Database:
    def save(self):
        print("保存到数据库...")

class Model(Logger, Database):
    def save(self):

print("正在验证...")
super().save()  # 调用 Logger.save()

model = Model()
model.save()
# 输出:
# 正在验证...
# 正在记录...
# 正在保存到数据库...

2. 混入类

MRO通过确保方法以正确的顺序被调用,使mixins变得强大:

class TimestampMixin:
    def save(self):
        self.updated_at = "2025-08-11"
        super().save()

class ValidationMixin:
    def save(self):
        if not hasattr(self, 'name'):
            raise ValueError("需要名称")
super().save()

class BaseModel:
    def save(self):
        print(f"正在保存 {self.name}{self.updated_at}")

class User(ValidationMixin, TimestampMixin, BaseModel):
    def __init__(self, name):
        self.name = name

user = User("Alice")
user.save()  # 验证,添加时间戳,然后保存
# 输出:正在保存 Alice 于 2025-08-11

3. 框架方法重写

像 Django 这样的 Web 框架使用方法解析顺序(MRO)来让你重写特定的行为,同时保留其他行为:

class BaseView:
    def get(self):
        return self.render()

    def render(self):
        return "基础渲染"

class AuthMixin:
    def get(self):
        if not self.is_authenticated():
            return "需要登录"
        return super().get()

    def is_authenticated(self):

return False

class MyView(AuthMixin, BaseView):
    def render(self):
        return "自定义渲染"

view = MyView()
print(view.get())  # "需要登录" - AuthMixin.get() 首先运行
print(MyView.__mro__)
# 显示: MyView -> AuthMixin -> BaseView -> object


🚀 关键要点

  • __mro__ 定义了继承层次结构中的方法查找顺序
  • 它通过 C3 线性化解决了菱形问题
  • 在多重继承中顺序很重要:class Child(Parent1, Parent2) 会先搜索 Parent1 然后是 Parent2
  • super() 遵循 MRO,而不仅仅是直接父类
  • 理解 MRO 对于设计有效的混入类和使用框架至关重要

记住:当有疑问时,检查 YourClass.__mro__ 以查看确切的查找顺序!

更多