Python - 抽象基类



Python 中的抽象基类 (ABC) 是一个不能直接实例化的类,旨在被子类化。ABC 通过提供所有子类都必须实现的通用接口来充当其他类的蓝图。

它们是 Python 中面向对象编程的基本部分,使开发人员能够为一组相关类定义和实施一致的 API。

抽象基类的用途

以下是对 Python 抽象基类的用途和功能的深入了解 -

定义标准接口

抽象基类 (ABC) 允许我们为其他类定义蓝图。此蓝图通过提供一致的接口来确保从抽象基类 (ABC) 派生的任何类都实现某些方法。

以下是在 Python 中定义抽象基类的标准接口的示例代码 -


from abc import ABC, abstractmethod

class Shape(ABC):
	 	@abstractmethod
	 	def area(self):
	 	 	 pass

	 	@abstractmethod
	 	def perimeter(self):
	 	 	 pass

强制实施

当类从抽象基类 (ABC) 继承时,它必须实现所有抽象方法。如果没有,则 Python 将引发 TypeError。以下是在 Python 中强制实现抽象基类的示例 -


class Rectangle(Shape):
	 	def __init__(self, width, height):
	 	 	 self.width = width
	 	 	 self.height = height

	 	def area(self):
	 	 	 return self.width * self.height

	 	def perimeter(self):
	 	 	 return 2 * (self.width + self.height)

# This will work
rect = Rectangle(5, 10)

# This will raise TypeError
class IncompleteShape(Shape):
	 	pass

为未来发展提供模板

抽象基类 (ABC) 在多个开发人员可能处理代码库的不同部分的大型项目中非常有用。它们为开发人员提供了一个明确的模板,以确保一致性并减少错误。

促进多态性

抽象基类 (ABC) 通过支持开发代码来使多态性成为可能,这些代码可以处理来自不同类的对象,只要它们符合特定的接口即可。此功能简化了代码的扩展和维护。

下面是 Facilitating Polymorphism in Abstract Base Class of Python 的示例 -


def print_shape_info(shape: Shape):
	 	print(f"Area: {shape.area()}")
	 	print(f"Perimeter: {shape.perimeter()}")

square = Rectangle(4, 4)
print_shape_info(square)

注意:要执行上述示例代码,必须定义标准接口和 Enforcing Implementation。

抽象基类的组件

Python 中的抽象基类 (ABC) 由几个关键组件组成,这些组件使它们能够定义和强制执行子类的接口。

这些组件包括 ABC 类、abstractmethod 装饰器和其他几个有助于创建和管理抽象基类的组件。以下是抽象基类的关键组件 -

  • ABC 类:Python 的抽象基类 (ABC) 模块中的这个类用作创建抽象基类的基础。从 ABC 派生的任何类都被视为抽象基类。
  • 'abstractmethod' 装饰器:abc 模块中的这个装饰器用于将方法声明为 abstract。这些方法在 ABC 中没有实现,必须在派生类中重写。
  • 'ABCMeta' 元类:这是 ABC 使用的元类。它负责跟踪哪些方法是抽象的,并确保如果未实现任何抽象方法,则无法创建抽象基类的实例。
  • ABC 中的具体方法:抽象基类还可以定义提供默认实现的具体方法。这些方法可以被子类使用或覆盖。
  • 实例化限制:ABC 的一个关键特性是,如果它们有任何抽象方法,则不能直接实例化它们。尝试使用未实现的抽象方法实例化 ABC 将引发 'TypeError'。
  • 子类验证:抽象基类 (ABC) 可以使用 issubclass 函数验证给定类是否为子类,并可以使用 isinstance 函数检查实例。

Python 中的抽象基类示例

以下示例显示了 ABC 如何强制执行方法实现、支持多态性并为相关类提供清晰一致的接口 -


from abc import ABC, abstractmethod

class Shape(ABC):
	 	@abstractmethod
	 	def area(self):
	 	 	 pass

	 	@abstractmethod
	 	def perimeter(self):
	 	 	 pass

	 	def description(self):
	 	 	 return "I am a shape."

class Rectangle(Shape):
	 	def __init__(self, width, height):
	 	 	 self.width = width
	 	 	 self.height = height

	 	def area(self):
	 	 	 return self.width * self.height

	 	def perimeter(self):
	 	 	 return 2 * (self.width + self.height)

class Circle(Shape):
	 	def __init__(self, radius):
	 	 	 self.radius = radius

	 	def area(self):
	 	 	 import math
	 	 	 return math.pi * self.radius ** 2

	 	def perimeter(self):
	 	 	 import math
	 	 	 return 2 * math.pi * self.radius

def print_shape_info(shape):
	 	print(shape.description())
	 	print(f"Area: {shape.area()}")
	 	print(f"Perimeter: {shape.perimeter()}")

shapes = [Rectangle(5, 10), Circle(7)]

for shape in shapes:
	 	print_shape_info(shape)
	 	print("-" * 20)

class IncompleteShape(Shape):
	 	pass

try:
	 	incomplete_shape = IncompleteShape()
except TypeError as e:
	 	print(e) 	

输出

在执行上述代码时,我们将得到以下输出 -

I am a shape.
Area: 50
Perimeter: 30
--------------------
I am a shape.
Area: 153.93804002589985
Perimeter: 43.982297150257104
--------------------
Can't instantiate abstract class IncompleteShape with abstract methods area, perimeter