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
廣告