Python多继承与MRO机制
一、多继承基础
Python支持多继承,一个类可以继承多个父类:
class Flyable:
def fly(self):
print(f"{self.__class__.__name__} 正在飞行")
class Swimmable:
def swim(self):
print(f"{self.__class__.__name__} 正在游泳")
class Duck(Flyable, Swimmable):
def quack(self):
print("嘎嘎嘎")
duck = Duck()
duck.fly() # Duck 正在飞行
duck.swim() # Duck 正在游泳
duck.quack() # 嘎嘎嘎
二、方法解析顺序(MRO)
当多个父类有同名方法时,Python使用C3线性化算法确定调用顺序:
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__)
# (, , , , )
d = D()
d.method() # B.method(按MRO顺序,B在C前面)
# MRO遵循的原则:
# 1. 子类优先于父类
# 2. 多个父类按声明顺序
# 3. 保持单调性(如果A在B前面,在所有子类中A都在B前面)
三、super()的工作原理
super()不是简单地调用父类方法,而是按MRO顺序调用下一个类的方法:
class Base:
def __init__(self):
print("Base.__init__")
class Left(Base):
def __init__(self):
print("Left.__init__")
super().__init__() # 调用MRO中的下一个,不一定是Base
class Right(Base):
def __init__(self):
print("Right.__init__")
super().__init__()
class Child(Left, Right):
def __init__(self):
print("Child.__init__")
super().__init__()
child = Child()
# 输出顺序:
# Child.__init__
# Left.__init__
# Right.__init__ (Left的super()调用的是Right,不是Base!)
# Base.__init__
# MRO: Child -> Left -> Right -> Base -> object
四、协作式多继承
正确使用多继承的关键是协作式设计:
class Shape:
def __init__(self, **kwargs):
# 消费自己需要的参数,传递剩余参数
super().__init__(**kwargs)
class ColorMixin:
def __init__(self, color='black', **kwargs):
self.color = color
super().__init__(**kwargs)
def describe_color(self):
return f"颜色: {self.color}"
class SizeMixin:
def __init__(self, width=0, height=0, **kwargs):
self.width = width
self.height = height
super().__init__(**kwargs)
def area(self):
return self.width * self.height
class BorderMixin:
def __init__(self, border_width=1, **kwargs):
self.border_width = border_width
super().__init__(**kwargs)
class Rectangle(ColorMixin, SizeMixin, BorderMixin, Shape):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def describe(self):
return f"矩形: {self.width}x{self.height}, {self.describe_color()}, 边框{self.border_width}px"
# 所有参数通过kwargs传递,每个类取自己需要的
rect = Rectangle(color='red', width=100, height=50, border_width=2)
print(rect.describe())
# 矩形: 100x50, 颜色: red, 边框2px
五、Mixin模式
Mixin是一种通过多继承为类添加功能的设计模式:
import json
import time
class SerializableMixin:
"""JSON序列化能力"""
def to_json(self):
return json.dumps(self.__dict__, default=str, ensure_ascii=False)
@classmethod
def from_json(cls, json_str):
data = json.loads(json_str)
return cls(**data)
class TimestampMixin:
"""自动时间戳"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.created_at = time.time()
self.updated_at = time.time()
def touch(self):
self.updated_at = time.time()
class ValidatableMixin:
"""数据验证能力"""
_validators = {}
def validate(self):
errors = []
for field, validator in self._validators.items():
value = getattr(self, field, None)
try:
validator(value)
except (ValueError, TypeError) as e:
errors.append(f"{field}: {e}")
if errors:
raise ValueError(f"验证失败: {'; '.join(errors)}")
return True
class ComparableMixin:
"""比较能力(需要子类定义_compare_key)"""
def _compare_key(self):
raise NotImplementedError
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self._compare_key() == other._compare_key()
def __lt__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self._compare_key() < other._compare_key()
def __hash__(self):
return hash(self._compare_key())
# 组合使用
class User(SerializableMixin, TimestampMixin, ValidatableMixin):
_validators = {
'name': lambda v: v and len(v) >= 2 or (_ for _ in ()).throw(ValueError("至少2个字符")),
'age': lambda v: 0 <= v <= 150 or (_ for _ in ()).throw(ValueError("必须在0-150之间")),
}
def __init__(self, name, age, **kwargs):
self.name = name
self.age = age
super().__init__(**kwargs)
user = User("Alice", 30)
print(user.to_json())
print(user.created_at)
六、菱形继承问题
class Logger:
def __init__(self):
self.log_entries = []
def log(self, message):
self.log_entries.append(message)
class FileLogger(Logger):
def __init__(self):
super().__init__()
self.filename = 'app.log'
def log(self, message):
super().log(message)
# 写入文件...
class ConsoleLogger(Logger):
def __init__(self):
super().__init__()
def log(self, message):
super().log(message)
print(message)
class DualLogger(FileLogger, ConsoleLogger):
"""同时输出到文件和控制台"""
def log(self, message):
super().log(message) # 按MRO调用
# MRO: DualLogger -> FileLogger -> ConsoleLogger -> Logger
# super()确保Logger.__init__只被调用一次
七、抽象基类与多继承
from abc import ABC, abstractmethod
class Readable(ABC):
@abstractmethod
def read(self) -> bytes:
pass
class Writable(ABC):
@abstractmethod
def write(self, data: bytes) -> int:
pass
class Seekable(ABC):
@abstractmethod
def seek(self, offset: int, whence: int = 0) -> int:
pass
class ReadWriteStream(Readable, Writable, Seekable):
"""必须实现所有抽象方法"""
def __init__(self):
self._buffer = bytearray()
self._position = 0
def read(self) -> bytes:
data = bytes(self._buffer[self._position:])
self._position = len(self._buffer)
return data
def write(self, data: bytes) -> int:
self._buffer.extend(data)
self._position = len(self._buffer)
return len(data)
def seek(self, offset: int, whence: int = 0) -> int:
if whence == 0:
self._position = offset
elif whence == 1:
self._position += offset
elif whence == 2:
self._position = len(self._buffer) + offset
return self._position
八、__init_subclass__替代方案
class PluginBase:
"""使用__init_subclass__替代元类实现插件注册"""
_plugins = {}
def __init_subclass__(cls, plugin_name=None, **kwargs):
super().__init_subclass__(**kwargs)
name = plugin_name or cls.__name__.lower()
cls._plugins[name] = cls
@classmethod
def get_plugin(cls, name):
return cls._plugins.get(name)
@classmethod
def list_plugins(cls):
return list(cls._plugins.keys())
class JSONProcessor(PluginBase, plugin_name='json'):
def process(self, data):
return json.dumps(data)
class XMLProcessor(PluginBase, plugin_name='xml'):
def process(self, data):
return f"{data}"
print(PluginBase.list_plugins()) # ['json', 'xml']
processor = PluginBase.get_plugin('json')()
print(processor.process({'key': 'value'}))
九、多继承的陷阱与规避
# 陷阱1:方法冲突
class A:
def action(self):
return "A的实现"
class B:
def action(self):
return "B的实现"
class C(A, B):
pass # C.action() 调用A的版本(按声明顺序)
# 规避:明确覆盖
class C(A, B):
def action(self):
# 明确选择或组合
result_a = A.action(self)
result_b = B.action(self)
return f"{result_a} + {result_b}"
# 陷阱2:__init__参数不兼容
# 规避:使用**kwargs协作式设计
# 陷阱3:状态冲突
class TimerMixin:
def __init__(self):
self.start_time = time.time() # 可能覆盖其他类的同名属性
# 规避:使用名称前缀
class TimerMixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._timer_start_time = time.time()
十、设计建议
1. 优先使用组合而非继承
2. Mixin类应该小而专注,只提供一种能力
3. Mixin类不应该有自己的状态(或最小化状态)
4. 使用**kwargs实现协作式__init__
5. 避免超过2-3层的继承深度
6. 使用ABC定义接口,Mixin添加实现
7. 当MRO变得复杂时,考虑重构为组合模式
# 组合优于继承的示例
class Logger:
def log(self, msg): pass
class Serializer:
def serialize(self, obj): pass
# 继承方式(紧耦合)
class Service(Logger, Serializer):
pass
# 组合方式(松耦合,更灵活)
class Service:
def __init__(self, logger=None, serializer=None):
self.logger = logger or Logger()
self.serializer = serializer or Serializer()
总结:多继承是Python的强大特性,但需要谨慎使用。理解MRO和super()的工作原理是正确使用多继承的前提。Mixin模式是多继承最常见且最安全的应用方式,它通过小而专注的类为目标类添加可复用的功能。
Python多继承与MRO机制