Python 支持多继承,即一个类可以同时继承多个父类。这种特性允许我们将多个相关的类组合在一起,以实现更复杂的功能。
在 Python 中,多继承的语法很简单,只需要在类定义时在类名后面用逗号分隔列出所有父类即可,例如:
class A:
def hello(self):
print('Hello from A')
class B:
def hello(self):
print('Hello from B')
class C(A, B):
pass
c = C()
c.hello() # 输出:Hello from A
在这个示例中,类 C 继承了类 A 和类 B,但是没有重写 hello() 方法。因此,当调用 c.hello() 时,C 的实例会使用 A 中定义的 hello() 方法,因为 A 在 B 前面,所以它先被搜索到。
class A:
def hello(self):
print('Hello from A')
class B:
def hello(self):
print('Hello from B')
class C(B, A):
pass
c = C()
c.hello() # 输出:Hello from B
当一个类继承了多个父类时,它可以重写和覆盖这些父类中的方法。如果多个父类中有同名的方法,Python 将按照一定的顺序来决定哪个方法会被调用,这个顺序由 MRO(Method Resolution Order)来决定,Python 使用 C3 算法来计算多继承中的 MRO。C3 算法采用广度优先搜索的策略,保证了搜索顺序的一致性和合理性。
MRO 算法的原则是尽可能地保持继承顺序不变,即先继承的类先被搜索,同级别的父类按照它们在类定义中出现的顺序被搜索。如果在搜索过程中出现了循环依赖的情况,Python 将抛出 Cannot create a consistent method resolution 的错误。
它通常表示多继承中存在循环依赖,即出现了钻石继承(Diamond Inheritance)的情况,如下示例:
class GrandFather(object):
def __init__(self):
self.x = 10
def _print(self):
print("grandfather's x=", self.x)
class Father(GrandFather):
def __init__(self):
super(Father).__init__()
self.x = 20
def _print(self):
print("father's x=", self.x)
class Child(GrandFather, Father):
def __init__(self):
super(Child).__init__()
self.x = 30
def _print(self):
print("Child's x=", self.x)
GrandFather()._print()
Father()._print()
Child()._print()
#TypeError: Cannot create a consistent method resolution order (MRO) for bases GrandFather, Father
需要修改为:
class Child(Father, GrandFather)
钻石继承指的是在一个继承关系中,某个类同时继承了两个或更多个父类,而这些父类又有一个共同的祖先类,因此在继承关系图中形成了一个钻石形状。
当 Python 解析这个继承关系时,它使用 C3 算法来计算方法解析顺序(Method Resolution Order, MRO),这个算法会尝试保证所有父类的方法都可以正确地被调用,并避免歧义和循环依赖问题。如果存在循环依赖的情况,Python 就无法保证 MRO 的正确性,就会抛出 Cannot create a consistent method resolution 的错误。
因此,在使用多继承需要注意:
1.避免钻石继承,可以使用菱形继承的方式,即让一个子类继承两个父类,而这两个父类分别继承自同一个父类。
2.明确调用父类的方法。在多继承中,如果多个父类中都有相同的方法,可以使用 super() 函数来调用父类的方法。super() 函数会按照 MRO 中的顺序调用父类的方法。
3.确定继承顺序。在定义多继承类时,需要明确指定父类的继承顺序。如果没有明确指定,Python 会按照一定的规则来计算 MRO。可以使用 mro 属性来查看类的 MRO。