跳到主要内容

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 的基本规则

  1. 子类优先于父类:子类的方法会覆盖父类的方法
  2. 从左到右:多个父类按照继承列表的顺序
  3. 深度优先,但保持单调性:避免重复和矛盾

C3 线性化算法

📌 算法原理

Python 使用 C3 线性化算法 来计算 MRO,这个算法确保:

  1. 局部优先级保持:如果 A 在 B 前面,那么在 MRO 中 A 也应该在 B 前面
  2. 单调性:子类的 MRO 应该保持父类 MRO 的相对顺序
  3. 无重复:每个类在 MRO 中只出现一次

📌 C3 算法步骤

对于类 C 继承自类 B1, B2, ..., BN:

MRO(C) = [C] + merge(MRO(B1), MRO(B2), ..., MRO(BN), [B1, B2, ..., BN])

merge 操作的规则:

  1. 取第一个列表的头部元素
  2. 如果这个元素不在其他列表的尾部,则将其加入结果
  3. 从所有列表中移除这个元素
  4. 重复直到所有列表为空

📌 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'>)

📌 菱形继承的问题

  1. 重复初始化:基类的__init__可能被调用多次
  2. 方法冲突:多个父类有同名方法时的选择问题
  3. 属性冲突:同名属性的覆盖问题

解决菱形继承问题

📌 使用 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 模式提供了一种优雅的代码复用方式。