python中的抽象类及多继承
一、抽象类
之前我们定义了Person类实现了eat()、sleep()方法,
每种人都会吃喝但是吃喝的地点不同,如果实现了方法体就浪费了。因此我们可以只定义eat()方法,不实现方法体,这种形式我们可以将方法定义为抽象方法,具有抽象方法的类就叫做抽象类。
抽象类是一个特殊的类,只能被继承,不能实例化,抽象类中可以有抽象方法和普通方法。
(1) .定义抽象类
定义抽象类需要导入 abc模块。
from abc import ABCMeta, abstractmethod
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
(2).定义抽象方法
抽象方法:只定义方法,不具体实现方法体。
在定义抽象方法时需要在前面加入:@abstractmethod
抽象方法不包含任何可实现的代码,因此其函数体通常使用pass。
@abstractmethod
def eat(self): pass
@abstractmethod
def sleep(self): pass
定义一个Animal抽象类,定义eat()、sleep()抽象方法,定义两个子类继承Animal抽象类。
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def eat(self): pass
@abstractmethod
def sleep(self): pass
def breathe(self):
print('呼吸空气')
class Dog(Animal):
def eat(self):
print('吃骨头')
def sleep(self):
print('睡狗窝')
class Cat(Animal):
def eat(self):
print('吃鱼')
def sleep(self):
print('睡猫舍')
dog = Dog()
dog.eat()
dog.sleep()
dog.breathe()
cat = Cat()
cat.eat()
cat.sleep()
cat.breathe()
输出为:
吃骨头
睡狗窝
呼吸空气
吃鱼
睡猫舍
呼吸空气
二、多继承
一个子类可以继承多个父类,就是多继承,并且拥有所有父类的属性和方法。
例如 孩子会继承自己的父亲和母亲的特征。
1、 语法
class 子类名(父类名1,父类名2…) : pass
class A(object):
def test1(self):
print('A---test1')
def test2(self):
print('A---test2')
class B(object):
def test3(self):
print('B---test3')
def test4(self):
print('B---test4')
class C(A,B):
pass
c=C()
c.test1()
c.test2()
c.test3()
c.test4()
输出为:
A---test1
A---test2
B---test3
B---test4
2、 多继承注意事项
如果子类和父类有相同的方法,就会调用子类中的方法。
如果不同的父类中存在着相同的方法名称,子类对象调用的时候会调用哪个父类中的方法呢? Python会根据 MRO(method resolution order) 方法解析顺序列表进行查找。
提示:开发时,需要避免这种容易产生混淆的情况!
如果父类之间存在同名的属性和方法,应尽量避免使用多继承。
class A(object):
def test1(self):
print('A---test1')
class B(object):
def test1(self):
print('B---test1')
class C(A,B):
pass
c=C()
c.test1()
print(C.mro())
输出为:
A---test1
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
3、 继承原理(钻石继承)
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止,而这个MRO列表的构造是通过一个C3线性化算法来实现的。
我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
注意:D类有两个选择,默认选择B类执行。
在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法广度优先,定义类时需要继承object,这样的类称为新式类,否则为旧式类
4、 多继承中super本质
不是直接查找父类,而是根据调用节点的广度优先顺序执行的。
创建A、B、C、D类,D类继承B,C类,B类继承A类,C类继承A类。在每个方法中都调用super().func()方法,查看执行顺序。
class A(object):
def test(self):
print(' A test')
class B(A):
def test(self):
super().test()
print(' B test')
class C(A):
def test(self):
super().test()
print(' C test')
class D(B, C):
def test(self):
super().test()
print(' D test')
d = D()
d.test()
print(D.mro())
输出为:
A test
C test
B test
D test
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]