一、抽象基类与接口
1、抽象基类(abstract base class,ABC)
提到这个概念,我们应该会马上联想到面向对象、继承。作为继承的一种,它拥有继承中代码共享、提高代码的重用性等优点。例如:
class Animal(object):
def eat(self):
print('吃饭')
class Dog(Animal):
pass
class Cat(Animal):
pass
animal=Animal()
animal.eat()
dog=Dog()
dog.eat()
cat=Cat()
cat.eat()
输出:
吃饭
吃饭
吃饭
狗(Dog)和猫(Cat)都属于动物(Animal),它们有很多类似的属性和动作,我们可以在父类中实现这些方法,在子类中直接继承或者重写父类中的方法,这样减少了代码的重复性,提高了代码的复用能力。
作为继承的一种,抽象基类有用继承的上述这些优点,但是它与普通的继承也有不同之处,
抽象基类不能实例化
子类需要实现基类指定的抽象方法
看到这里,我们会感觉抽象基类有一种接口的感觉。
抽象基类的主要是功能就是类似于Java等编程语言中的接口。但是需要明确一点,Python语言中没有interface这个概念,这只是一种约定俗成的编程规范,就如同Python也没有真实意义上的私有变量,我们在编程中可以规范的使用下划线来表示某个变量为私有变量。
2、接口
接口(Interface)是对象公开方法的一种集合,在Java中通常以interface关键字来定义,接口虽然实现过程中和类相似,但是却具有不同的概念。具体而言,类与接口主要有以下几点不同之处:
类实现了对象的属性和方法,而接口指定了使用该接口需要实现哪些方法
类可以实例化,而接口不可以被实例化
类中的方法可以是实现,接口中的方法都是抽象方法
3、抽象基类的实现
Python标准库中有一个模块abc可以实现抽象基类和抽象方法,它们的实现方式如下:
4、特别注意
抽象基类 :通过继承abc模块中的ABC类来实现抽象基类。
抽象方法 :通过装饰器abstractmethod来声明抽象方法。
含有abstractmethod的类不能被实例化,集成了含abstractmethod方法的子类必须包含(重写)abstractmethod装饰的方法,没有被装饰的可以不重写。
1、例如,定义一个飞机的抽象基类
from abc import ABC,abstractmethod
#定义一个飞机的抽象基类
#抽象基类是不能直接被实例化的
class AirPlane(ABC):
@abstractmethod
def fly(self):
pass
@abstractmethod
def oil(self):
pass
class FightPlane(AirPlane):
def __init__(self,name):
self.name=name
def shoot(self):
print(self.name,'攻击')
class TransPlane(AirPlane):
def __init__(self,name):
self.name=name
def load(self):
print(self.name,'攻击')
if __name__ == '__main__':
plane_b=FightPlane('战斗机')
plane_b.shoot()
plane_c=TransPlane('运输机')
plane_c.load()
报错:
plane_a=AirPlane()
TypeError: Can't instantiate abstract class AirPlane with abstract methods fly, oil
2、例如,定义战斗机和运输机并且继承飞机的抽象基类
from abc import ABC,abstractmethod
#定义一个飞机的抽象基类
#抽象基类是不能直接被实例化的
class AirPlane(ABC):
@abstractmethod
def fly(self):
pass
@abstractmethod
def oil(self):
pass
class FightPlane(AirPlane):
def __init__(self,name):
self.name=name
class TransPlane(AirPlane):
def __init__(self,name):
self.name=name
if __name__ == '__main__':
plane_b=FightPlane('战斗机')
plane_b.shoot()
plane_c=TransPlane('运输机')
plane_c.load()
执行结果:
plane_b=FightPlane('战斗机')
TypeError: Can't instantiate abstract class FightPlane with abstract methods fly, oil
3、例如,定义战斗机和运输机重写基类中的抽象方法并且继承飞机的抽象基类
from abc import ABC,abstractmethod
#定义一个飞机的抽象基类
#抽象基类是不能直接被实例化的
class AirPlane(ABC):
@abstractmethod
def fly(self):
pass
@abstractmethod
def oil(self):
pass
class FightPlane(AirPlane):
def __init__(self,name):
self.name=name
# 必须要实现抽象基类的抽象方法,不然实例化会报错
def fly(self):
print(self.name, '飞行')
# 必须要实现抽象基类的抽象方法,不然实例化会报错
def oil(self):
print(self.name, '加油')
#自己的方法
def shoot(self):
print(self.name,'攻击')
class TransPlane(AirPlane):
def __init__(self,name):
self.name=name
# 必须要实现抽象基类的抽象方法,不然实例化会报错
def fly(self):
print(self.name, '飞行')
# 必须要实现抽象基类的抽象方法,不然实例化会报错
def oil(self):
print(self.name, '加油')
#自己的方法
def load(self):
print(self.name,'攻击')
if __name__ == '__main__':
plane_b=FightPlane('战斗机')
plane_b.shoot()
plane_c=TransPlane('运输机')
plane_c.load()
输出:
战斗机 攻击
运输机 攻击