python面向对象-继承
(一)单继承:
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类或派生类(Subclass),而被继承的class称为父类或基类(Base class、Super class)。
比如,我们已经编写了一个名为Animal的class,有一个eat()方法可以直接打印:
1 class Animal(object): 2 def eat(self): 3 print("Animal is eating")
当我们需要编写Dog或
Cat
类时,就可以直接从Animal
类继承:
1 class Dog(Animal): 2 pass 3 4 5 class Cat(Animal): 6 pass
对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。
继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial实现了eat()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了eat()方法:
1 d1 = Dog() 2 d1.eat() 3 4 c1 = Cat() 5 c1.eat()
运行结果如下:
1 Animal is eating 2 Animal is eating
当然,也可以对子类增加一些方法,比如Dog类:
1 class Dog(Animal): 2 def eat(self): 3 print("Dog is eating meat") 4 5 def bark(self): 6 print("Dog is barking")
当子类和父类都存在相同的eat()
方法时,我们说,子类的eat()
覆盖了父类的eat()
,在代码运行的时候,总是会调用子类的eat()
。这样,我们就获得了继承的另一个好处:多态。我们可以理解为子类把父类的代码复制到了自己里面。
此时 d1.eat() 的输出是: Dog is eating meat
我们再添加一个Hasky类继承Dog类,
1 class Hasky(Dog): 2 pass
当Hasky类的实例调用eat方法时,
1 h1 = Hasky() 2 h1.eat()
寻找eat方法遵循自下而上的顺序(我们把继承关系看成一颗倒立的树),因此运行结果是: Dog is eating meat
(二)多继承:
Python中允许一个类同时继承多个类,那么在阅读别人写的代码时就遇到一个问题,有时一个方法在多个类中都有实现,我们如何寻找正确的实现呢?
(1)首先看一个简单的例子,C1同时继承C2,C3:
1 class C3(object): 2 def f1(self): 3 print("C3.f1") 4 5 6 class C2(object): 7 def f1(self): 8 print("C2.f1") 9 10 11 class C1(C2, C3): 12 pass 13 14 obj_c1 = C1() 15 obj_c1.f1()
Python在寻找f1的实现时遵循从左至右的原则(选在C2里找,然后在C3里):
因此程序运行结果是: C2.f1
(2)我们再来看一个稍微复杂的例子,加入上例中C2还继承了一个C4类,而C3与C4对同一个方法f2都有实现,Python如何处理呢?
1 class C4(object): 2 def f2(self): 3 print("C4.f2") 4 5 6 class C3(object): 7 def f1(self): 8 print("C3.f1") 9 10 def f2(self): 11 print("C3.f2") 12 13 14 class C2(C4): 15 def f1(self): 16 print("C2.f1") 17 18 19 class C1(C2, C3): 20 pass 21 22 obj_c1 = C1() 23 obj_c1.f2()
按照上面的例1,Python首先在C2里寻找,而C2没有f2方法,这时有两条路,往上找C4,或者往右找C3,
从实际运行结果看,Python遵循深度优先原则,如下图所示:
程序运行结果: C4.f2
(3)我们再看一个相对复杂的例子,类继承关系如下图:
假如C5和C3里都有一个f3方法,代码如下:
1 class C5(object): 2 def f3(self): 3 print("C5.f3") 4 5 6 class C4(C5): 7 def f2(self): 8 print("C4.f2") 9 10 11 class C3(C5): 12 def f1(self): 13 print("C3.f1") 14 15 def f2(self): 16 print("C3.f2") 17 18 def f3(self): 19 print("C3.f3") 20 21 22 class C2(C4): 23 def f1(self): 24 print("C2.f1") 25 26 27 class C1(C2, C3): 28 pass 29 30 obj_c1 = C1() 31 obj_c1.f3()
那么obj_c1.f3()会使用哪个类的f3呢?按照我们在例2中深度优先的原则,应该是C5的f3,可是程序运行结果却是 C3.f3
这里有一个原因,当C4和C3有共同父类时,父类里是最后才寻找的。实际搜寻顺序如下图的数字: