继承

在 Python 中,类可以从一个或多个父类继承:

1
2
3
4
5
class Parent:
pass

class Child(Parent):
pass

当一个类从多个父类继承时,这就是多重继承

1
2
3
class A: pass
class B: pass
class C(A, B): pass

C 同时继承了 AB

MRO

MRO(方法解析顺序)

是指 Python 在多重继承中搜索属性和方法的顺序

当你访问 obj.method() 时,Python 会按一定的顺序在类的继承链上查找 method,这个顺序由 MRO 列表 决定。

查看 MRO

两种常用方法:

1
2
C.__mro__  # 返回一个元组
C.mro() # 返回一个列表

示例:

1
2
3
4
5
6
class A: pass
class B: pass
class C(A, B): pass

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

解释:

Python 会优先从当前类开始,然后按 MRO 顺序依次查找父类。

计算方式

Python 3 使用 C3 Linearization 算法 来计算 MRO。

它的核心规则是:

  1. 自己优先,子类优先于父类;
  2. 保持继承声明顺序
  3. 保证继承一致性,不会破坏父类顺序。

📘 举例:经典菱形继承问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A:
def show(self): print("A")

class B(A):
def show(self): print("B")

class C(A):
def show(self): print("C")

class D(B, C):
pass

d = D()
d.show()
print(D.__mro__)

输出:

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

解释

  • Python 查找顺序:D → B → C → A → object;
  • 虽然 A 是共同父类,避免重复调用,但只会执行一次;
  • 这就是 C3 MRO 的结果。

super() 用法

super() 是用来根据 MRO 顺序调用下一个类的方法的函数。

基本用法

1
2
3
4
5
6
7
8
9
10
11
class Parent:
def greet(self):
print("Hello from Parent")

class Child(Parent):
def greet(self):
super().greet()
print("Hello from Child")

c = Child()
c.greet()

输出:

1
2
Hello from Parent
Hello from Child

✅ super() 根据 MRO 调用“下一个”类的同名方法,而不是“父类固定名字”。

真正威力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A:
def show(self):
print("A")

class B(A):
def show(self):
print("B")
super().show()

class C(A):
def show(self):
print("C")
super().show()

class D(B, C):
def show(self):
print("D")
super().show()

d = D()
d.show()
print(D.__mro__)

输出:

1
2
3
4
5
D
B
C
A
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

解释:

  • MRO 决定了调用链顺序:D → B → C → A → object
  • 每个类的 super().show() 都按照 MRO 链往后找;
  • 不会重复调用同一个类,例如 A.show() 只执行一次。

👉 所以 super() 并不是“调用父类”,而是“根据 MRO 查找下一个类”。

底层机制

在底层,super() 实际上做了两件事:

1
super(CurrentClass, self)
  1. 取出 self 的 MRO;
  2. 从 MRO 中找到 CurrentClass 之后的下一个类;
  3. 从那个类开始继续查找方法。

🔍 验证

1
2
3
4
5
6
print(D.mro())
# [D, B, C, A, object]

# 调用 super(B, d)
super(B, d).show()
# 会跳过 B,从 C 开始查找 -> 输出 "C"

super() 而不是写父类名?

错误写法:

1
2
3
class B(A):
def show(self):
A.show(self) # ❌ 不推荐

问题:

  • 会固定调用指定父类,不遵循MRO
  • 在多重继承中,可能破坏调用链,导致重复调用或遗漏。

正确写法:

1
super().show()  # ✅ 自动遵循 MRO,安全

混合继承

Mixin 类通常用来组合功能,不会单独实例化,使用 super() 能确保每个 Mixin 的方法都能被执行一次。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class LogMixin:
def save(self):
print("Logging...")
super().save()

class SaveMixin:
def save(self):
print("Saving data...")
super().save()

class Base:
def save(self):
print("Base save done.")

class Model(LogMixin, SaveMixin, Base):
pass

m = Model()
m.save()
print(Model.__mro__)

输出:

1
2
3
4
Logging...
Saving data...
Base save done.
(<class '__main__.Model'>, <class '__main__.LogMixin'>, <class '__main__.SaveMixin'>, <class '__main__.Base'>, <class 'object'>)

✅ 所有类的方法都执行了一次,顺序由 MRO 控制。

菱形继承

1
2
3
4
5
  A
/ \
B C
\ /
D

MRO: [D, B, C, A, object]

super() 调用顺序:

1
D.show() → B.show() → C.show() → A.show()

每个类都只执行一次。

总结表

概念 含义 关键点
MRO 方法解析顺序 决定属性/方法查找路径
算法 C3 线性化 保证一致性和单次调用
super() 调用 MRO 链中的下一个类 不直接指向父类
单继承 super() = 父类调用 简单
多继承 super() = 按 MRO 向后 避免重复调用
不推荐 Parent.method(self) 会破坏 MRO 链