Python Multi-Inheritance [Python多重继承]
虽然 Python 不是一个专门的面向对象的语言,但是 Python 仍然有着优秀的封装,继承,多态的机制。其中继承尤其是多重继承是在复杂项目中经常用到的。但是多重继承在使用的过程中有很多需要注意的地方,以至于很多开发人员都会尽量避免使用多重继承。
Python 支持多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法。如下代码:
class A:
def test_a(self):
print('Test function of A')
class B:
def test_b(self):
print('Test function of B')
class C(A, B):
pass
# __base__ 这个属性可以用来获取当前类的所有父类
print(C.__base__)
# printout: (<class '__main__.A'>, <class '__main__.B'>)
c = C()
c.test_a()
# printout: Test function of A
c.test_b()
# printout: Test function of B
在多重继承中,如果多个父类中有同名方法,则会优先第一个父类[在上面代码中,如果有同名方法,就会优先使用 A 的]。
考虑下图的复杂情况,D
继承了A,B,C
,同时,C
还继承了A
和B
。此时,如果要调用D.test()
,则现在D
本身寻找,如果没有则在第一个父类[也就是 A]中寻找,如果没有则会去A
的第一个父类[也就是 Object
]中寻找。如果还是没有,则去第二个父类B
中寻找,然后再去B
的父类[Object
]中寻找,这里因为刚才已经找过一个Object
这里就会跳过。依然没有找到test
方法的话,最后会寻找C
,及其父类A
和B
,但是因为A
和B
都找过了,所以仍然会跳过。可以看出多重继承,调用方法的过程会相对复杂。
在具体开发中,多重继承会让代码变得复杂。如果必须使用,建议 Mixin 方式
在设计类的继承关系时,通常,主线都是单一继承下来的。但是,如果需要混入额外的功能,通过多重继承可以实现。比如,Dog
类可以继承是Animal
,但是有一个“特殊”的能力就是Runnable
。此时,Runnable
就是一个额外混入的功能,毕竟不只是 Dog 才能 Runnable,但是也不是所有的 Animal 都可以 Runnable。
所以为了更好地看出继承关系,可以把 Runnable
改为 RunnableMixin
。类似的,你还可以定义出肉食动物 CarnivorousMixin
和草食动物 HerbivoresMixin
,让某个动物同时拥有好几个 Mixin。这样Dog
这个类就可以写成:
class Dog(Animal, RunnableMixin, CarnivorousMixin):
pass
这样一来,即便在复杂项目中不得不使用多重继承时,也不需要设计复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。