大家好,我是正在实战各种 AI 项目的程序员晚枫。

你在写类的时候,第一反应是继承还是组合? 说实话,我以前也是"继承狂魔"——能继承就继承,觉得这样代码复用率最高。后来踩了一堆坑才知道,组合才是王道,但继承也有它的用武之地。今天咱们就把 MRO、super()、Mixin 这些搞透彻。


🧬 MRO 方法解析顺序:多重继承的寻路地图

钻石继承问题

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

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

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

class D(B, C): # 钻石继承:D → B → C → A
pass

print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
d = D()
d.method() # B —— 按 MRO 顺序查找,先找到 B

💡 MRO 是什么? Method Resolution Order,方法解析顺序。Python 使用 C3 线性化算法来确定多重继承时方法的查找顺序。你可以把它理解为一张"寻路地图"——Python 按这个顺序依次查找方法。

查看 MRO 的两种方式

1
2
3
4
5
6
7
# 方式1:__mro__ 属性(元组)
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

# 方式2:mro() 方法(列表)
print(D.mro())
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]

MRO 不合法的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ❌ 这种继承顺序会报错
class X:
pass

class Y(X):
pass

# class Z(X, Y): # TypeError: Cannot create a consistent MRO!
# pass

# 原因:X 在 Y 之前,但 Y 继承自 X,矛盾!
# ✅ 正确顺序
class Z(Y, X): # 先 Y 后 X,Y 继承 X,不矛盾
pass

🔧 super():不是调用父类,而是调用 MRO 中的下一个

super() 的真实行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class A:
def method(self):
print("A.method")
super().method() # 调用 MRO 中的下一个

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

class C(A):
def method(self):
print("C.method")
# 没有 super() 调用,链条到此为止

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

d = D()
d.method()
# D.method → B.method → C.method
# 注意:A.method 没被调用!因为 C 没调 super()

print(D.__mro__)
# D → B → C → A → object

super() 在 __init__ 中的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Base:
def __init__(self, **kwargs):
print("Base.__init__")
super().__init__(**kwargs)

class A(Base):
def __init__(self, a_val, **kwargs):
print(f"A.__init__(a_val={a_val})")
super().__init__(**kwargs)

class B(Base):
def __init__(self, b_val, **kwargs):
print(f"B.__init__(b_val={b_val})")
super().__init__(**kwargs)

class Child(A, B):
def __init__(self, a_val, b_val, **kwargs):
print("Child.__init__")
super().__init__(a_val=a_val, b_val=b_val, **kwargs)

c = Child(a_val=1, b_val=2)
# Child.__init__
# A.__init__(a_val=1)
# B.__init__(b_val=2)
# Base.__init__

⚠️ 关键点super() 不是调用"父类",而是调用 MRO 链中的下一个类。配合 **kwargs 可以让所有 __init__ 都被调用到。


🧩 Mixin 模式:即插即用的功能模块

什么是 Mixin?

Mixin 是一种特殊的类,它不单独使用,而是被混入到其他类中提供可选功能。它不是"is-a"关系,而是"can-do"关系。

实用 Mixin 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import json

class JSONSerializableMixin:
"""提供 JSON 序列化功能的 Mixin"""
def to_json(self):
return json.dumps(self.__dict__, ensure_ascii=False, indent=2)

@classmethod
def from_json(cls, json_str):
data = json.loads(json_str)
return cls(**data)

class ReprMixin:
"""提供友好 repr 的 Mixin"""
def __repr__(self):
class_name = self.__class__.__name__
attrs = ', '.join(f'{k}={v!r}' for k, v in self.__dict__.items())
return f'{class_name}({attrs})'

class ComparableMixin:
"""提供比较功能的 Mixin"""
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__dict__ == other.__dict__

def __ne__(self, other):
return not self.__eq__(other)

# 组合使用多个 Mixin
class User(JSONSerializableMixin, ReprMixin, ComparableMixin):
def __init__(self, name, age):
self.name = name
self.age = age

u = User("Alice", 30)
print(u) # User(name='Alice', age=30)
print(u.to_json()) # {"name": "Alice", "age": 30}
print(u == User("Alice", 30)) # True

Mixin 设计原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ✅ 好的 Mixin:单一职责、无状态依赖
class LogMixin:
"""日志 Mixin"""
def log(self, message):
print(f"[{self.__class__.__name__}] {message}")

class ValidateMixin:
"""验证 Mixin"""
def validate(self):
for key, value in self.__dict__.items():
if value is None:
raise ValueError(f"{key} 不能为空")
return True

# ❌ 坏的 Mixin:依赖特定属性、多职责
class BadMixin:
"""这个 Mixin 假设宿主类有特定属性,不通用"""
def process(self):
# 假设宿主有 self.data 和 self.config
return self.data + self.config # 脆弱!

⚖️ 继承 vs 组合:什么时候用什么

一张表看明白

维度继承组合
关系is-a(是一个)has-a(有一个)
耦合度
灵活性编译时确定运行时可变
复用性白盒(可见内部)黑盒(只看接口)
适用场景确实有层次关系只需要某些功能

实战对比:鸭子问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# ❌ 继承(不推荐):橡皮鸭不会叫,但被迫继承了 quack
class Duck:
def quack(self):
print("Quack!")
def fly(self):
print("Flying!")

class RubberDuck(Duck):
def quack(self): # 覆盖
print("Squeak!")
def fly(self): # 覆盖
raise NotImplementedError("橡皮鸭不会飞!")

# ✅ 组合(推荐):行为可以灵活替换
class QuackBehavior:
def quack(self):
print("Quack!")

class SqueakBehavior:
def quack(self):
print("Squeak!")

class MuteBehavior:
def quack(self):
print("...(沉默)")

class FlyBehavior:
def fly(self):
print("Flying!")

class NoFlyBehavior:
def fly(self):
print("不会飞")

class Duck:
def __init__(self, quack_behavior, fly_behavior):
self.quack_behavior = quack_behavior
self.fly_behavior = fly_behavior

def perform_quack(self):
self.quack_behavior.quack()

def perform_fly(self):
self.fly_behavior.fly()

# 真鸭
real_duck = Duck(QuackBehavior(), FlyBehavior())
real_duck.perform_quack() # Quack!
real_duck.perform_fly() # Flying!

# 橡皮鸭
rubber_duck = Duck(SqueakBehavior(), NoFlyBehavior())
rubber_duck.perform_quack() # Squeak!
rubber_duck.perform_fly() # 不会飞

什么时候用继承?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ✅ 适合继承:确实是 is-a 关系
class Animal:
def __init__(self, name):
self.name = name

class Dog(Animal): # 狗是一种动物 ✅
def bark(self):
print("Woof!")

class Cat(Animal): # 猫是一种动物 ✅
def meow(self):
print("Meow!")

# ✅ 适合继承:框架要求
class FlaskView: # Flask 要求继承
pass

class MyView(FlaskView):
pass

🎯 本讲总结

MRO:C3 线性化算法决定方法查找顺序。用 __mro__ 查看,避免矛盾的继承顺序。

**super()**:不是调用父类,而是调用 MRO 中的下一个类。配合 **kwargs 确保所有 __init__ 被调用。

Mixin 模式:提供可选功能的"即插即用"模块,单一职责、不依赖宿主内部结构。

继承 vs 组合:优先使用组合,继承只用于真正的 is-a 关系或框架要求。


📚 推荐教材

《Python 编程从入门到实践(第 3 版)》 | 《流畅的 Python(第 2 版)》 | 《CPython 设计与实现》

学习路线: 零基础 → 《从入门到实践》 → 《流畅的 Python》 → 本门课程 → 《CPython 设计与实现》


🎓 加入《流畅的 Python》直播共读营

学到这里,如果你想系统吃透这本书——欢迎加入我的直播共读课。

  • 每周直播精讲,逐章拆解核心知识点
  • 专属学习群,随时答疑交流
  • 试运营特惠:499 元299 元

👉 【立即报名《流畅的 Python》共读课】https://mp.weixin.qq.com/s/ivHJwn1nNx5ug4TFrapvGg

🔗 课程导航

上一讲:序列和多态 | 下一讲:接口与协议


💬 联系我

平台账号/链接
微信扫码加好友
B 站Python 自动化办公社区

主营业务:AI 编程培训、企业内训、技术咨询

🎓 AI 编程实战课程

想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!

fluent-python.png