抽象基类是 Python 中的特殊类型的类。它们允许程序员定义一个基类,作为其他类继承的模板。Python 中抽象基类和普通类的区别在于,对于抽象基类,你不希望基类的消费者能够创建基类本身的实例。抽象基类只作为一个蓝图。子类是提供该蓝图的具体实现的手段。除此之外,你可以强制约束基类中的某些方法,让子类必须实现。
带有继承性的简单类
class Vehicle:
def __init__(self):
super().__init__()
def go_forward(self):
print('Driving forward.')
class Car(Vehicle):
def __init__(self):
super().__init__()
class Truck(Vehicle):
def __init__(self):
super().__init__()
vehicle1 = Vehicle()
car1 = Car()
car1.go_forward()
truck1 = Truck()
truck1.go_forward()
Driving forward.
Driving forward.
上面这段代码是一个简单的车辆类和两个额外的类,汽车和卡车。我们希望这个程序是可扩展的,以便可以添加新的汽车或卡车类型。我们当然可以不使用抽象基类来创建这样的程序。事实上,上面的代码似乎是有效的。当我们在汽车和卡车对象上调用被继承的方法时,它们都向前行驶。请注意,我们还实例化了一个Vehicle对象。其实我们并不需要这样做,因为汽车和卡车不需要创建Vehicle的实例就可以做它们需要做的一切。我们可以把这段代码修改一下,利用一个抽象基类来完成一些事情。
添加抽象基类
要在 Python 中使用一个抽象基类,你需要导入ABC和abstractmethod,正如我们在这里看到的。
from abc import ABC, abstractmethod
继承自 Abc 表明这是一个抽象基类。
这里的Vehicle类有一个<class 'abc.ABCMeta'>的类型。
from abc import ABC, abstractmethod
class Vehicle(ABC):
def __init__(self):
super().__init__()
将一个方法声明为抽象,需要一个子类来实现它
from abc import ABC, abstractmethod
class Vehicle(ABC):
def __init__(self):
super().__init__()
@abstractmethod
def go_forward(self):
pass
上面的语法有点特别。我们可以看到 @abstractmethod 装饰符,它告诉 Python,这个方法需要由任何继承自抽象基类的子类来实现。
抽象基类不能被实例化
由于Vehicle现在已经继承了ABC,所以它不能再被实例化了。如果我们尝试,Python 会抛出一个错误。
vehicle1 = Vehicle()
Traceback (most recent call last):
File "C:/python/justhacking/abc.py", line 38, in <module>
vehicle1 = Vehicle()
TypeError: Can't instantiate abstract class Vehicle with abstract methods go_forward
添加一个子类
让我们创建一个汽车[类的例子],它现在继承于 Vehicle。由于我们使用 ABC 模块在 Vehicle 类上设置了一些规则,你会看到如果我们没有用所需的属性或方法创建子类,Python 会输出一个错误。
class Car(Vehicle):
pass
car1 = Car()
Traceback (most recent call last):
File "C:/python/justhacking/abc.py", line 38, in <module>
car1 = Car(True)
TypeError: Can't instantiate abstract class Car with abstract methods go_forward
Python 现在正在强制执行这样一个事实:如果我们想有一个 Vehicle 的子类,它必须实现 go_forward() 方法。让我们再试一下。
class Car(Vehicle):
def __init__(self, press_accelerator):
super().__init__()
self.press_accelerator = press_accelerator
def go_forward(self):
if self.press_accelerator:
print('Driving forward')
else:
print('Press the accelerator to drive forward')
car1 = Car(True)
car1.go_forward()
Driving forward
第二个子类
我们可以创建一个不同的Truck子类,它也继承自Vehicle的抽象基类。
from abc import ABC, abstractmethod
class Vehicle(ABC):
def __init__(self):
super().__init__()
@abstractmethod
def go_forward(self):
pass
class Truck(Vehicle):
def __init__(self, press_accelerator):
super().__init__()
self.press_accelerator = press_accelerator
def go_forward(self):
if self.press_accelerator:
print('Driving forward')
else:
print('Press the accelerator to drive forward')
truck1 = Truck(False)
truck1.go_forward()
truck2 = Truck(True)
truck2.go_forward()
Press the accelerator to drive forward
Driving forward
抽象基类是一个非常有用的工具,它可以在任何给定类的消费者中强制执行一系列的约束。抽象基类值得花时间去尝试,以了解其潜在的好处。
- 抽象类是指可以被继承的类,但避免实现具体的方法,只留下子类必须实现的方法签名。
- 抽象类对于在高层定义和执行类的抽象是很有用的,类似于类型化语言中的接口概念,不需要方法实现。
- 通过abc模块,我们可以防止子类在未能覆盖其父类和祖类的抽象类方法时被实例化。