第58集:多继承

学习目标

  • 理解多继承的概念和语法
  • 掌握多继承的方法查找顺序(MRO)
  • 学会使用super()处理多继承
  • 理解菱形继承问题
  • 掌握Mixin模式
  • 学会设计合理的多继承结构

一、多继承概述

1.1 什么是多继承

多继承:一个子类可以同时继承多个父类,获得多个父类的属性和方法。

1.2 多继承的语法

class Child(Parent1, Parent2, ...):
    pass

1.3 基本示例

class Father:
    def father_method(self):
        print("父亲的方法")

class Mother:
    def mother_method(self):
        print("母亲的方法")

class Child(Father, Mother):
    pass

c = Child()
c.father_method()  # 输出:父亲的方法
c.mother_method()  # 输出:母亲的方法

二、方法查找顺序(MRO)

2.1 MRO的概念

MRO(Method Resolution Order):方法解析顺序,Python使用C3算法确定方法的查找顺序。

2.2 查看MRO

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):
    pass

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

d = D()
d.method()  # 输出:B(按MRO顺序查找)

2.3 MRO查找规则

查找顺序:深度优先,从左到右

    A
   / \
  B   C
   \ /
    D

MRO(D) = [D, B, C, A, object]

2.4 复杂示例

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

class B(A):
    pass

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

class D(B, C):
    pass

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

d = D()
d.method()  # 输出:C
# 查找过程:D -> B -> C (找到method)

三、菱形继承问题

3.1 什么是菱形继承

菱形继承结构:

        A
       / \
      B   C
       \ /
        D

3.2 传统继承的问题

class A:
    def __init__(self):
        print("A的初始化")

class B(A):
    def __init__(self):
        super().__init__()
        print("B的初始化")

class C(A):
    def __init__(self):
        super().__init__()
        print("C的初始化")

class D(B, C):
    def __init__(self):
        super().__init__()
        print("D的初始化")

d = D()
# 输出:
# A的初始化
# C的初始化
# B的初始化
# D的初始化

# A的初始化只执行了一次,避免了重复

3.3 MRO解决菱形继承

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

class B(A):
    pass

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

class D(B, C):
    pass

# 查看MRO
for cls in D.__mro__:
    print(cls, end=" -> ")
# 输出:<class '__main__.D'> -> <class '__main__.B'> -> 
#       <class '__main__.C'> -> <class '__main__.A'> -> <class 'object'>

四、使用super()处理多继承

4.1 super()在多继承中的作用

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

class B(A):
    def method(self):
        super().method()  # 调用MRO中下一个类的方法
        print("B")

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

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

d = D()
d.method()
# 输出:
# A
# C
# B
# D

4.2 协作多继承

class Flyable:
    def fly(self):
        print("可以飞行")

class Swimmable:
    def swim(self):
        print("可以游泳")

class Duck(Flyable, Swimmable):
    def quack(self):
        print("嘎嘎叫")

duck = Duck()
duck.fly()    # 输出:可以飞行
duck.swim()   # 输出:可以游泳
duck.quack()  # 输出:嘎嘎叫

五、Mixin模式

5.1 什么是Mixin

Mixin:一种特殊的多继承设计模式,用于向类添加功能,而不是作为主要继承层次的一部分。

5.2 Mixin的特点

  1. 通常以Mixin结尾
  2. 不包含__init__方法
  3. 不包含实例属性
  4. 只提供方法

5.3 Mixin示例

class LoggingMixin:
    """日志Mixin"""
    
    def log(self, message):
        print(f"[LOG] {message}")

class CachingMixin:
    """缓存Mixin"""
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._cache = {}
    
    def get_cache(self, key):
        return self._cache.get(key)
    
    def set_cache(self, key, value):
        self._cache[key] = value

class Service(LoggingMixin, CachingMixin):
    """服务类"""
    
    def process_data(self, data):
        self.log(f"处理数据: {data}")
        cached = self.get_cache(data)
        if cached:
            self.log("从缓存获取")
            return cached
        result = f"处理后的{data}"
        self.set_cache(data, result)
        self.log("结果已缓存")
        return result

service = Service()
result1 = service.process_data("data1")
result2 = service.process_data("data1")  # 从缓存获取

5.4 实际应用:功能组合

class SerializableMixin:
    """可序列化Mixin"""
    
    def to_dict(self):
        return self.__dict__
    
    @classmethod
    def from_dict(cls, data):
        obj = cls()
        obj.__dict__.update(data)
        return obj

class ValidatableMixin:
    """可验证Mixin"""
    
    def validate(self):
        raise NotImplementedError("子类必须实现validate方法")

class User(SerializableMixin, ValidatableMixin):
    """用户类"""
    
    def __init__(self, name, email, age):
        self.name = name
        self.email = email
        self.age = age
    
    def validate(self):
        if not self.name or len(self.name) < 2:
            return False, "姓名长度不能小于2"
        if '@' not in self.email:
            return False, "邮箱格式不正确"
        if self.age < 0 or self.age > 150:
            return False, "年龄不合法"
        return True, "验证通过"

# 使用
user = User("张三", "zhangsan@example.com", 25)
print(user.to_dict())

is_valid, message = user.validate()
print(f"验证结果: {is_valid}, {message}")

六、完整示例

6.1 智能家居系统

class Light:
    """灯光控制"""
    
    def turn_on(self):
        print("灯光已打开")
    
    def turn_off(self):
        print("灯光已关闭")

class TemperatureControl:
    """温度控制"""
    
    def set_temperature(self, temp):
        print(f"温度已设置为{temp}°C")

class MusicPlayer:
    """音乐播放"""
    
    def play(self, song):
        print(f"正在播放: {song}")
    
    def stop(self):
        print("音乐已停止")

class SmartHome(Light, TemperatureControl, MusicPlayer):
    """智能家居"""
    
    def morning_mode(self):
        """早晨模式"""
        self.turn_on()
        self.set_temperature(25)
        self.play("轻音乐")
    
    def night_mode(self):
        """夜间模式"""
        self.turn_off()
        self.set_temperature(22)
        self.stop()

# 使用
home = SmartHome()
home.morning_mode()
print()
home.night_mode()

6.2 数据库接口

class Connectable:
    """可连接Mixin"""
    
    def connect(self):
        print("已连接到数据库")

class Queryable:
    """可查询Mixin"""
    
    def query(self, sql):
        print(f"执行查询: {sql}")

class Transactionable:
    """可事务Mixin"""
    
    def begin_transaction(self):
        print("开始事务")
    
    def commit(self):
        print("提交事务")
    
    def rollback(self):
        print("回滚事务")

class Database(Connectable, Queryable, Transactionable):
    """数据库类"""
    
    def __init__(self, host, port):
        self.host = host
        self.port = port
    
    def execute(self, sql):
        self.begin_transaction()
        try:
            self.query(sql)
            self.commit()
        except Exception as e:
            print(f"错误: {e}")
            self.rollback()

# 使用
db = Database("localhost", 3306)
db.connect()
db.execute("SELECT * FROM users")

七、常见错误与注意事项

7.1 常见错误

  1. 方法名冲突:
class A:
    def method(self):
        print("A的方法")

class B:
    def method(self):
        print("B的方法")

class C(A, B):
    pass

c = C()
c.method()  # 只调用A的方法,B的方法被覆盖
  1. 复杂的MRO:
# 过于复杂的继承层次难以理解和维护
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
class E(C, B): pass  # 可能导致MRO错误

7.2 注意事项

  1. 避免过度使用多继承
  2. 理解MRO查找顺序
  3. 合理使用super()
  4. 考虑使用Mixin模式
  5. 优先考虑组合而非继承

八、课后练习

练习题

  1. 编程题

    • 定义一个FlyableSwimmableMixin
    • 创建一个同时能飞和能游的类
    • 实现相关方法
  2. 编程题

    • 定义一个可序列化和可验证的Mixin
    • 创建一个使用这些Mixin的类
    • 实现相应功能
  3. 思考题

    • 什么时候应该使用多继承?
    • 什么是Mixin模式?
    • 如何避免菱形继承问题?

九、本集总结

核心知识点回顾

  1. 多继承:一个类可以继承多个父类
  2. MRO:方法解析顺序,使用C3算法
  3. 菱形继承:通过MRO解决重复继承问题
  4. **super()**:在多继承中正确调用父类方法
  5. Mixin模式:通过多继承组合功能

下集预告

下一集我们将学习多态特性,深入了解如何通过方法重写实现多态。


学习建议: 理解多继承的工作原理,特别是MRO查找顺序。谨慎使用多继承,优先考虑组合和Mixin模式。

« 上一篇 方法重写 下一篇 » 多态特性