(一)单继承

在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遵循深度优先原则,如下图所示:

Python继承 函数名相同参数不同 python继承关系_父类

程序运行结果: C4.f2

(3)我们再看一个相对复杂的例子,类继承关系如下图:

 

Python继承 函数名相同参数不同 python继承关系_Python_02

假如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有共同父类时,父类里是最后才寻找的。实际搜寻顺序如下图的数字:

Python继承 函数名相同参数不同 python继承关系_子类_03