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__
以查看确切的查找顺序!