编程后端开发者

在Python中,类继承时的方法解析顺序(MRO - Method Resolution Order)机制是如何工作的?理解方法解析顺序的重要性是什么,如何知道或更改它?

用 Hintsage AI 助手通过面试

答案

方法解析顺序(MRO)是Python中的一种机制,确定在多重继承的情况下,搜索方法和属性时类的查找顺序。

C3线性化(C3 linearization)是构造方法解析顺序的算法。理解MRO对于设计复杂类层次结构至关重要,以避免歧义和方法的意外行为。

可以使用__mro__属性或mro()函数来查询任何类的MRO:

class A: def hello(self): print('A') class B(A): def hello(self): print('B') class C(A): def hello(self): print('C') class D(B, C): pass print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) obj = D() obj.hello() # 'B', 因为B在MRO中比C靠前

MRO不能显式更改,但可以控制基类的列举顺序。

具有陷阱的问题

如果一个类从多个父类继承,方法将以什么顺序被调用?例如:

class Base: def foo(self): print('Base') class Left(Base): def foo(self): print('Left') super().foo() class Right(Base): def foo(self): print('Right') super().foo() class Child(Left, Right): pass Child().foo()

许多人期望“foo”会从Left被调用,然后是Right,然后是Base——确实如此。然而,如果改变基类的顺序(class Child(Right, Left)),顺序将会改变!

正确的答案:

调用顺序将如MRO所定义。在第一种情况下——Left,Right,Base。MRO是通过特定算法(C3线性化)构建的:

[Child, Left, Right, Base, object]

由于对主题细节了解不足而导致的实际错误示例


故事

逻辑的多重继承,方法覆盖

开发团队使用多重继承来实现mixins。结果发现,由于基类顺序不正确,混入的通用逻辑被子类“覆盖”,部分业务逻辑未执行,导致数据丢失。


故事

调用了错误的父类方法

在终结方法(__del__)中,预期将调用基类的方法。然而,由于对MRO的错误理解,调用了另一个继承的mixing方法,在这里没有进行资源清理,导致了内存泄漏。


故事

在不理解调用链的情况下使用super()

在Python 3项目中,客户重写了部分多重继承的代码,却忘记更新通过super()的调用。这导致了无限递归的情况,方法不断自我调用,因方法解析顺序的错误而引发。