多重继承
Python 支持一个类继承多个父类。这带来了强大的表达能力,但也增加了复杂性——尤其是方法解析顺序(MRO)的理解。
基本语法
class Flyer(object):
def fly(self):
return "Flying"
class Swimmer(object):
def swim(self):
return "Swimming"
class Duck(Flyer, Swimmer):
pass
d = Duck()
print d.fly() # Flying
print d.swim() # Swimming
Duck(Flyer, Swimmer) 表示 Duck 同时继承 Flyer 和 Swimmer。Duck 实例可以调用两个父类的方法。
方法解析顺序(MRO)
当多个父类有同名方法时,Python 需要决定调用哪个。这个决定规则就是方法解析顺序。
旧式类(Python 2 默认)
旧式类(不继承 object)使用深度优先、从左到右的顺序:
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
d = D()
print d.method() # B,深度优先:D -> B -> A -> C
旧式类的 MRO 简单但不处理"菱形继承"(diamond problem)——当两个父类继承自同一个祖父类时,祖父类的方法可能被访问两次。
新式类(继承 object)
新式类使用C3 线性化算法,生成更合理的 MRO:
class A(object):
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
d = D()
print d.method() # B
print D.__mro__ # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
D.__mro__ 属性显示完整的方法解析顺序:D -> B -> C -> A -> object。C3 算法保证:
- 子类在父类之前
- 多个父类按声明顺序
- 每个类只出现一次
super() 与多重继承
super() 按 MRO 调用下一个类的方法,在多重继承中特别有用:
class A(object):
def __init__(self):
print "A.__init__"
self.a = 1
class B(A):
def __init__(self):
print "B.__init__"
super(B, self).__init__() # 调用 MRO 中的下一个类
self.b = 2
class C(A):
def __init__(self):
print "C.__init__"
super(C, self).__init__()
self.c = 3
class D(B, C):
def __init__(self):
print "D.__init__"
super(D, self).__init__()
self.d = 4
d = D()
print D.__mro__
# D.__init__
# B.__init__
# C.__init__
# A.__init__
注意 super(B, self).__init__() 调用的是 C.__init__,不是 A.__init__!因为 D 的 MRO 是 D -> B -> C -> A -> object,B 的下一个类是 C。
菱形继承
class Base(object):
def __init__(self):
print "Base.__init__"
class Left(Base):
def __init__(self):
print "Left.__init__"
super(Left, self).__init__()
class Right(Base):
def __init__(self):
print "Right.__init__"
super(Right, self).__init__()
class Bottom(Left, Right):
def __init__(self):
print "Bottom.__init__"
super(Bottom, self).__init__()
b = Bottom()
# Bottom.__init__
# Left.__init__
# Right.__init__
# Base.__init__
Base.__init__ 只被调用一次,这是 C3 MRO 的优势。如果用旧式类或不用 super(),Base 可能被调用两次。
多重继承的设计建议
- 优先用组合替代多重继承:"有一个"比"是一个"更灵活
- Mixin 模式:设计只提供特定功能的轻量级父类
- 避免深层继承链:继承超过 3 层时考虑重构
- 始终使用新式类:旧式类的 MRO 行为不可预测
# Mixin 示例
class JSONSerializable(object):
def to_json(self):
import json
return json.dumps(self.__dict__)
class Timestamped(object):
def __init__(self):
from datetime import datetime
self.created_at = datetime.now()
class User(JSONSerializable, Timestamped):
def __init__(self, name):
super(User, self).__init__()
Timestamped.__init__(self)
self.name = name
u = User("Alice")
print u.to_json() # {"name": "Alice", "created_at": "..."}