Python教程38:多重继承与MRO
“大道至简,大巧若拙。”
Python支持多重继承,一个类可以继承多个父类。今天我们学习多重继承的机制、方法解析顺序(MRO)以及如何避免常见陷阱。
1. 什么是多重继承
单继承 vs 多重继承
1# 单继承:一个父类
2class Parent:
3 pass
4
5class Child(Parent):
6 pass
7
8# 多重继承:多个父类
9class Father:
10 def skill(self):
11 return "父亲的技能"
12
13class Mother:
14 def talent(self):
15 return "母亲的天赋"
16
17class Child(Father, Mother):
18 """继承两个父类"""
19 pass
20
21# 子类拥有所有父类的方法
22c = Child()
23print(c.skill()) # 父亲的技能
24print(c.talent()) # 母亲的天赋
2. 方法解析顺序(MRO)
当多个父类有同名方法时,Python如何决定调用哪个?
基本规则
1class A:
2 def method(self):
3 return "A的方法"
4
5class B:
6 def method(self):
7 return "B的方法"
8
9class C(A, B):
10 """继承顺序:A, B"""
11 pass
12
13c = C()
14print(c.method()) # A的方法(优先使用第一个父类)
15
16# 查看MRO
17print(C.__mro__)
18# (<class 'C'>, <class 'A'>, <class 'B'>, <class 'object'>)
MRO(Method Resolution Order):
- 方法解析顺序
- 决定方法查找的顺序
- 遵循C3线性化算法
C3线性化算法
Python使用C3算法确定MRO:
1class A:
2 pass
3
4class B(A):
5 pass
6
7class C(A):
8 pass
9
10class D(B, C):
11 """菱形继承"""
12 pass
13
14# 查看MRO
15print(D.__mro__)
16# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
17# 规则:D -> B -> C -> A -> object
MRO规则:
- 子类在父类前
- 如果有多个父类,按照继承顺序
- 父类的父类在后
3. 菱形继承问题
什么是菱形继承
1class A:
2 """顶层基类"""
3 def method(self):
4 print("A.method")
5
6class B(A):
7 """左分支"""
8 def method(self):
9 print("B.method")
10 super().method()
11
12class C(A):
13 """右分支"""
14 def method(self):
15 print("C.method")
16 super().method()
17
18class D(B, C):
19 """继承B和C,形成菱形"""
20 def method(self):
21 print("D.method")
22 super().method()
23
24# A
25# / \
26# B C
27# \ /
28# D
29
30d = D()
31d.method()
32# 输出:
33# D.method
34# B.method
35# C.method
36# A.method
37
38# MRO确保A.method只调用一次
39print(D.__mro__)
40# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
super()的工作原理
1class A:
2 def __init__(self):
3 print("A.__init__")
4 super().__init__()
5
6class B(A):
7 def __init__(self):
8 print("B.__init__")
9 super().__init__()
10
11class C(A):
12 def __init__(self):
13 print("C.__init__")
14 super().__init__()
15
16class D(B, C):
17 def __init__(self):
18 print("D.__init__")
19 super().__init__()
20
21d = D()
22# 输出:
23# D.__init__
24# B.__init__
25# C.__init__
26# A.__init__
27
28# super()沿着MRO链向下调用,不是调用父类!
4. Mixin模式
Mixin是多重继承的常用模式:
1class JSONMixin:
2 """JSON序列化Mixin"""
3 def to_json(self):
4 import json
5 return json.dumps(self.__dict__)
6
7class XMLMixin:
8 """XML序列化Mixin"""
9 def to_xml(self):
10 items = ''.join(f"<{k}>{v}</{k}>" for k, v in self.__dict__.items())
11 return f"<object>{items}</object>"
12
13class Person:
14 """基类"""
15 def __init__(self, name, age):
16 self.name = name
17 self.age = age
18
19class SerializablePerson(Person, JSONMixin, XMLMixin):
20 """可序列化的Person"""
21 pass
22
23# 使用
24p = SerializablePerson("Alice", 25)
25print(p.to_json()) # {"name": "Alice", "age": 25}
26print(p.to_xml()) # <object><name>Alice</name><age>25</age></object>
Mixin命名规范:
- 类名以Mixin结尾
- 提供特定功能
- 不单独实例化
- 与其他类组合使用
5. 实战示例
示例:日志和序列化Mixin
1import json
2import datetime
3
4class LogMixin:
5 """日志Mixin"""
6 def log(self, message):
7 timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
8 print(f"[{timestamp}] {self.__class__.__name__}: {message}")
9
10class SerializeMixin:
11 """序列化Mixin"""
12 def to_dict(self):
13 return {k: v for k, v in self.__dict__.items() if not k.startswith('_')}
14
15 def to_json(self):
16 return json.dumps(self.to_dict(), default=str)
17
18 @classmethod
19 def from_dict(cls, data):
20 return cls(**data)
21
22class User:
23 """用户基类"""
24 def __init__(self, username, email):
25 self.username = username
26 self.email = email
27
28 def update_email(self, email):
29 self.email = email
30
31class EnhancedUser(User, LogMixin, SerializeMixin):
32 """增强的用户类"""
33 def update_email(self, email):
34 old = self.email
35 super().update_email(email)
36 self.log(f"邮箱从{old}更新为{email}")
37
38# 使用
39user = EnhancedUser("alice", "alice@old.com")
40user.log("用户创建")
41print(user.to_json())
42
43user.update_email("alice@new.com")
44print(user.to_json())
6. 多重继承最佳实践
1. 避免过深的继承层次
1# 不好:过深的多重继承
2class A: pass
3class B(A): pass
4class C(A): pass
5class D(B, C): pass
6class E(D): pass # 太复杂
7
8# 好:简单的继承关系
9class Base: pass
10class Mixin1: pass
11class Mixin2: pass
12class Derived(Base, Mixin1, Mixin2): pass
2. Mixin应该是独立的
1# 好:独立的Mixin
2class TimestampMixin:
3 """时间戳Mixin - 不依赖其他类"""
4 def __init__(self):
5 self.created_at = datetime.datetime.now()
6 super().__init__() # 调用链中的下一个
7
8# 不好:依赖特定基类的Mixin
9class BadMixin:
10 def some_method(self):
11 # 假设基类有specific_attr
12 return self.specific_attr # 耦合度高
3. 明确继承顺序
1# 好:清晰的顺序
2class MyClass(BaseClass, Mixin1, Mixin2, Mixin3):
3 """
4 继承顺序:
5 1. BaseClass - 主要功能
6 2. Mixin1, Mixin2, Mixin3 - 附加功能
7 """
8 pass
7. 小结
今天我们学习了多重继承:
- 多重继承:继承多个父类
- MRO:方法解析顺序,C3算法
- 菱形继承:super()确保每个类只调用一次
- Mixin模式:组合功能的常用模式
- 最佳实践:保持简单,Mixin独立
多重继承是强大但复杂的特性,需谨慎使用。
练习题:
- 创建一个可序列化、可验证、可日志的User类(使用3个Mixin)
- 分析给定类的MRO,理解继承顺序
- 重构一个使用多重继承的代码,简化继承关系
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
