提到这个概念,我们应该会马上联想到面向对象、继承。作为继承的一种,它拥有继承中代码共享、提高代码的重用性等优点。例如:
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也没有真实意义上的私有变量,我们在编程中可以规范的使用下划线来表示某个变量为私有变量。
接口(Interface)是对象公开方法的一种集合,在Java中通常以interface关键字来定义,接口虽然实现过程中和类相似,但是却具有不同的概念。具体而言,类与接口主要有以下几点不同之处:
类实现了对象的属性和方法,而接口指定了使用该接口需要实现哪些方法
类可以实例化,而接口不可以被实例化
类中的方法可以是实现,接口中的方法都是抽象方法
Python标准库中有一个模块abc可以实现抽象基类和抽象方法,它们的实现方式如下:
抽象基类 :通过继承abc模块中的ABC类来实现抽象基类。
抽象方法 :通过装饰器abstractmethod来声明抽象方法。
含有abstractmethod的类不能被实例化,集成了含abstractmethod方法的子类必须包含(重写)abstractmethod装饰的方法,没有被装饰的可以不重写。
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
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
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()
输出:
战斗机 攻击
运输机 攻击