
核心价值:覆盖面试高频考点,从「多继承基础」→「MRO 解决的问题」→「C3 算法逐步骤拆解」→「面试真题模拟」,用可视化代码示例与面试官视角的提问逻辑,彻底攻克 Python 多继承这一面试痛点。
Python 与 Java/C# 等单继承语言最大的差异在于支持多继承—— 一个子类可以同时继承多个父类。这种灵活性带来了两个核心问题:
这些问题直接考察候选人对 Python底层机制的理解深度,因此成为大厂 Python 岗的高频面试题。
# 语法:class 子类(父类1, 父类2, ...)
class Father:
def speak(self):
print("Father speaks")
class Mother:
def speak(self):
print("Mother speaks")
class Child(Father, Mother):
pass
child = Child()
child.speak() # 输出?问题:Child 实例调用speak()时,会优先执行 Father 还是 Mother 的方法?
这是多继承最典型的问题场景:
class A: # 祖父类
def func(self):
print("A.func")
class B(A): # 父类1继承A
def func(self):
print("B.func")
super().func()
class C(A): # 父类2继承A
def func(self):
print("C.func")
super().func()
class D(B, C): # 子类继承B和C,形成菱形
def func(self):
print("D.func")
super().func()
d = D()
d.func() # 输出顺序?问题:
func()时,A 会被执行几次?MRO(Method Resolution Order) 即方法解析顺序——Python 解释器在多继承场景下查找方法的固定规则。它确保:
Python 版本 | MRO 算法 | 特点 |
|---|---|---|
2.2 之前 | 深度优先搜索(DFS) | 菱形继承中祖父类会被多次执行,存在二义性 |
2.2-2.7 | 经典类用 DFS,新式类用 C3 算法 | 经典类无__mro__属性,默认不继承 object |
3.x | 所有类都是新式类,统一使用 C3 算法 | 默认继承 object,支持__mro__属性和mro()方法 |
# 方式1:类属性 __mro__(返回元组)
print(D.__mro__)
# 输出:(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
# 方式2:类方法 mro()(返回列表)
print(D.mro())
# 输出:[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]验证菱形继承的输出:
d = D()
d.func()
# 输出:D.func → B.func → C.func → A.func
# 符合MRO顺序,A仅被执行一次C3 算法的设计遵循三个原则:
C3 算法通过合并父类的 MRO 列表来生成当前类的 MRO。计算过程可总结为:
对于类
C(B1, B2, ..., Bn),其 MRO 列表为[C] + merge(MRO(B1), MRO(B2), ..., MRO(Bn), [B1, B2, ..., Bn])
其中,merge操作是核心,规则如下:
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): passobject,MRO 为[object]A继承自object:MRO(A) = [A, object]B继承自A:MRO(B) = [B] + merge(MRO(A), [A]) = [B, A, object]C继承自A:MRO(C) = [C] + merge(MRO(A), [A]) = [C, A, object]D继承自B和C:MRO(D) = [D] + merge(MRO(B), MRO(C), [B, C])三个列表为:
MRO(B) = [B, A, object]MRO(C) = [C, A, object][B, C]merge 操作:
B,检查是否在其他列表尾部→不在→加入 MRO (D),删除所有列表中的B
[A, object][C][D, B]C,检查是否在其他列表尾部→不在→加入 MRO (D),删除所有列表中的C
[][D, B, C]A,检查是否在其他列表尾部→列表 2 的头部是A→不在→加入 MRO (D),删除所有列表中的A
[object][object][D, B, C, A]object→加入 MRO (D),所有列表清空
[D, B, C, A, object]结果验证:与代码运行的__mro__一致。
class X: pass
class Y: pass
class A(X, Y): pass
class B(Y, X): pass
class M(A, B): pass # 这里会报错吗?计算 MRO (M):MRO(M) = [M] + merge(MRO(A), MRO(B), [A, B])MRO(A) = [A, X, Y, object]MRO(B) = [B, Y, X, object]
merge 时,候选元素 A 在 B 的 MRO 中是尾部元素([B, Y, X, object]的第三个元素是 X,不是 A)→加入。但后续会发现 X 在 B 的 MRO 中是尾部元素,Y 在 A 的 MRO 中是尾部元素,导致 merge 失败,最终 Python 会抛出TypeError:Cannot create a consistent method resolution order (MRO) for bases X, Y。
面试考点:这是面试官常考的 “非法多继承” 场景,考察对 C3 算法冲突的理解。
回答要点:
__mro__或mro()查看。回答要点:
回答要点:
题目:分析以下代码的输出顺序,并解释原因。
class Base:
def __init__(self):
print("Base.__init__")
class A(Base):
def __init__(self):
print("A.__init__")
super().__init__()
class B(Base):
def __init__(self):
print("B.__init__")
super().__init__()
class C(A, B):
def __init__(self):
print("C.__init__")
super().__init__()
c = C()答案:输出顺序:C.__init__ → A.__init__ → B.__init__ → Base.__init__原因:C 的 MRO 是[C, A, B, Base, object],super()会按照 MRO 顺序调用下一个类的方法。
在多继承中,super()的行为完全由 MRO 决定 —— 它会沿着 MRO 顺序寻找下一个类的同名方法,而非直接调用父类的方法。这是很多开发者容易误解的点。
错误代码:
class A:
def func(self):
print("A")
class B(A):
def func(self):
print("B")
super(A, self).func() # 错误:super()的第一个参数应该是当前类
b = B()
b.func() # 报错正确理解:super () 的第一个参数是 “起点类”,Python 会从 MRO 中该类的下一个类开始查找。
class C(B, A):
def func(self):
print("C")
super(B, self).func() # 从MRO中B的下一个类(即A)开始查找
# MRO(C) = [C, B, A, object]
c = C()
c.func() # 输出:C → A通过本文的系统学习,你将彻底掌握 Python 多继承、MRO 与 C3 算法的核心原理,并能轻松应对面试中的各类问题。