Python 多继承详解
注意
只有 CSSE1001 的学生会学习,CSSE7030 不会学这一部分
多继承的基本概念
多继承(Multiple Inheritance) 是指一个类可以同时继承多个父类的特性。Python 支持多继承,这使得类的设计更加灵活,但也带来了复杂性。
📌 多继承语法
class 子类(父类1, 父类2, 父类3, ...):
# 子类的定义
pass
📌 基本示例
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
class Flyable:
def fly(self):
return f"{self.name} is flying"
class Swimmable:
def swim(self):
return f"{self.name} is swimming"
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name)
def speak(self):
return f"{self.name} says quack!"
# 使用多继承
duck = Duck("Donald")
print(duck.speak()) # Donald says quack!
print(duck.fly()) # Donald is flying
print(duck.swim()) # Donald is swimming
方法解析顺序(MRO)
📌 什么是 MRO?
方法解析顺序(Method Resolution Order, MRO) 是 Python 确定在多继承情况下调用哪个方法的算法。当子类和多个父类都有同名方法时,Python 需要决定调用哪一个。
📌 查看 MRO
class A:
def method(self):
print("A.method")
class B(A):
def method(self):
print("B.method")
class C(A):
def method(self):
print("C.method")
class D(B, C):
pass
# 查看MRO
print(D.__mro__)
# 输出: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
print(D.mro())
# 输出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
# 调用方法
d = D()
d.method() # 输出: B.method
📌 MRO 的基本规则
- 子类优先于父类:子类的方法会覆盖父类的方法
- 从左到右:多个父类按照继承列表的顺序
- 深度优先,但保持单调性:避免重复和矛盾
C3 线性化算法
📌 算法原理
Python 使用 C3 线性化算法 来计算 MRO,这个算法确保:
- 局部优先级保持:如果 A 在 B 前面,那么在 MRO 中 A 也应该在 B 前面
- 单调性:子类的 MRO 应该保持父类 MRO 的相对顺序
- 无重复:每个类在 MRO 中只出现一次
📌 C3 算法步骤
对于类 C 继承自类 B1, B2, ..., BN:
MRO(C) = [C] + merge(MRO(B1), MRO(B2), ..., MRO(BN), [B1, B2, ..., BN])
merge 操作的规则:
- 取第一个列表的头部元素
- 如果这个元素不在其他列表的尾部,则将其加入结果
- 从所有列表中移除这个元素
- 重复直到所有列表为空
📌 C3 算法示例
class A: pass
class B: pass
class C(A, B): pass
class D(B, A): pass
# 尝试创建多继承类
try:
class E(C, D): pass
except TypeError as e:
print(f"错误: {e}")
# 输出: Cannot create a consistent method resolution order (MRO) for bases A, B
分析:
- C 的 MRO: [C, A, B, object]
- D 的 MRO: [D, B, A, object]
- 合并时发现 A 和 B 的顺序冲突,无法创建一致的 MRO
菱形继承问题
📌 什么是菱形继承?
菱形继承(Diamond Inheritance) 是指继承关系形成菱形结构,即一个基类被多个路径继承。
class Animal:
def __init__(self, name):
self.name = name
print(f"Animal.__init__({name})")
def speak(self):
return "Some sound"
class Mammal(Animal):
def __init__(self, name):
super().__init__(name)
print(f"Mammal.__init__({name})")
def speak(self):
return "Mammal sound"
class Bird(Animal):
def __init__(self, name):
super().__init__(name)
print(f"Bird.__init__({name})")
def speak(self):
return "Bird sound"
class Bat(Mammal, Bird):
def __init__(self, name):
super().__init__(name)
print(f"Bat.__init__({name})")
# 创建实例
bat = Bat("Bruce")
# 输出:
# Animal.__init__(Bruce)
# Bird.__init__(Bruce)
# Mammal.__init__(Bruce)
# Bat.__init__(Bruce)
print(Bat.__mro__)
# 输出: (<class '__main__.Bat'>, <class '__main__.Mammal'>, <class '__main__.Bird'>, <class '__main__.Animal'>, <class 'object'>)
📌 菱形继承的问题
- 重复初始化:基类的
__init__可能被调用多次 - 方法冲突:多个父类有同名方法时的选择问题
- 属性冲突:同名属性的覆盖问题
解决菱形继承问题
📌 使用 super()正确处理
class Animal:
def __init__(self, name, **kwargs):
self.name = name
print(f"Animal.__init__({name})")
super().__init__(**kwargs) # 调用下一个类的__init__
class Mammal(Animal):
def __init__(self, name, warm_blooded=True, **kwargs):
self.warm_blooded = warm_blooded
print(f"Mammal.__init__({name})")
super().__init__(name, **kwargs)
class Bird(Animal):
def __init__(self, name, can_fly=True, **kwargs):
self.can_fly = can_fly
print(f"Bird.__init__({name})")
super().__init__(name, **kwargs)
class Bat(Mammal, Bird):
def __init__(self, name, **kwargs):
print(f"Bat.__init__({name})")
super().__init__(name, **kwargs)
# 创建实例
bat = Bat("Bruce")
# 输出:
# Bat.__init__(Bruce)
# Mammal.__init__(Bruce)
# Bird.__init__(Bruce)
# Animal.__init__(Bruce)
print(f"Name: {bat.name}")
print(f"Warm blooded: {bat.warm_blooded}")
print(f"Can fly: {bat.can_fly}")
📌 使用协作继承模式
class Animal:
def __init__(self, name, **kwargs):
self.name = name
super().__init__(**kwargs)
def describe(self):
return f"I am {self.name}"
class Mammal(Animal):
def __init__(self, **kwargs):
self.warm_blooded = True
super().__init__(**kwargs)
def describe(self):
return super().describe() + ", a warm-blooded mammal"
class Bird(Animal):
def __init__(self, **kwargs):
self.has_wings = True
super().__init__(**kwargs)
def describe(self):
return super().describe() + ", a bird with wings"
class Bat(Mammal, Bird):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def describe(self):
return super().describe() + ", and I can fly!"
# 使用
bat = Bat(name="Bruce")
print(bat.describe())
# 输出: I am Bruce, a warm-blooded mammal, a bird with wings, and I can fly!
📚 总结
| 概念 | 说明 |
|---|---|
| 多继承 | 一个类继承多个父类的特性 |
| MRO | 方法解析顺序,决定方法调用的优先级 |
| C3 线性化 | Python 用于计算 MRO 的算法 |
| 菱形继承 | 继承关系形成菱形结构的问题 |
多继承是 Python 的强大特性,但需要谨慎使用。理解 MRO 和 C3 算法有助于避免常见问题,而 Mixin 模式提供了一种优雅的代码复用方式。