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) 通过支持开发能够操作来自不同类的对象的代码来实现多态性,只要这些对象符合特定的接口即可。此功能简化了代码的扩展和维护。

以下是 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)

注意:要执行上述示例代码,需要定义标准接口并强制实现。

抽象基类的组成部分

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

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

  • ABC 类:此类来自 Python 的抽象基类 (ABC) 模块,是创建抽象基类的基础。任何从 ABC 派生的类都被认为是抽象基类。
  • 'abstractmethod' 装饰器:此装饰器来自 abc 模块,用于将方法声明为抽象方法。这些方法在 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
广告