@abstractmethod 是 Python 标準库中的一个装饰器,位于 abc 模组内,用来定义 抽象方法 (abstract methods)。抽象方法是指必须在子类别中实作的方法,而在基类 (abstract base class, ABC) 中只能定义方法名称和规范,不能有具体的实作内容。

使用 @abstractmethod 可以确保某些方法在子类别中被实作,否则子类别无法被实例化。

  • 为什么使用 @abstractmethod?
    • 强制规范子类别行为:定义出子类别必须实作的方法,确保程式的一致性。
    • 设计更清晰的接口:提供方法签名的模板,指导子类别的开发。
    • 避免基类被实例化:基类仅作为框架存在,防止直接使用。
  • @abstractmethod 的基本语法引入 ABC 和 @abstractmethod
    • ABC 是 Python 的内建抽象基类,它用来辅助定义抽象类别。
    • @abstractmethod 装饰器标注抽象方法。范例

    from abc import ABC, abstractmethod

    class Animal(ABC):
    @abstractmethod
    def sound(self):
    pass # 不定义具体实作,只是声明

    @abstractmethod
    def move(self):
    pass

    # Animal 是抽象类别,无法直接实例化
    # animal = Animal() # TypeError: Can\'t instantiate abstract class Animal with abstract methods

    子类别必须实作所有抽象方法,否则无法实例化

    class Dog(Animal):
    def sound(self):
    return "Woof!"

    def move(self):
    return "Run"

    dog = Dog()
    print(dog.sound()) # Woof!
    print(dog.move()) # Run

  • 抽象类别中的具体方法抽象类别可以包含 具体方法,这些方法不需要在子类别中实作。只有被 @abstractmethod 标注的方法是必须实作的。
  • 范例

    class Shape(ABC):
    def description(self):
    return "This is a shape."

    @abstractmethod
    def area(self):
    pass

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

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

    rect = Rectangle(4, 5)
    print(rect.description()) # This is a shape.
    print(rect.area()) # 20

  • @abstractmethod 与多型抽象基类通常用于设计多型行为。抽象方法定义了接口,允许不同的子类别在具体实作中表现出不同的行为。
  • 范例

    class Payment(ABC):
    @abstractmethod
    def pay(self, amount):
    pass

    class CreditCardPayment(Payment):
    def pay(self, amount):
    return f"Paid {amount} using Credit Card."

    class PayPalPayment(Payment):
    def pay(self, amount):
    return f"Paid {amount} using PayPal."

    # 支付方式可依不同类别动态改变
    def process_payment(payment: Payment, amount):
    print(payment.pay(amount))

    process_payment(CreditCardPayment(), 100) # Paid 100 using Credit Card.
    process_payment(PayPalPayment(), 200) # Paid 200 using PayPal.

  • 子类别中使用 super() 与 @abstractmethod如果需要在子类别中扩展抽象基类的方法,可以使用 super() 调用基类的部分功能。
  • 范例

    class Animal(ABC):
    @abstractmethod
    def sound(self):
    pass

    class Cat(Animal):
    def sound(self):
    super().sound() # 调用基类的空方法(仅示例,实际基类方法通常有意义)
    return "Meow!"

    cat = Cat()
    print(cat.sound()) # Meow!

  • 抽象属性除了方法,@abstractmethod 也可以用来定义抽象属性,这样子类别需要提供具体的属性值。
  • 范例

    class Vehicle(ABC):
    @property
    @abstractmethod
    def wheels(self):
    pass

    class Car(Vehicle):
    @property
    def wheels(self):
    return 4

    car = Car()
    print(car.wheels) # 4

  • 常见问题
    • 为什么基类无法实例化?如果基类中有未实作的抽象方法,则基类是抽象类别,无法直接使用。
    • 可以只实作部分抽象方法吗?不行。子类别必须实作所有的抽象方法,否则子类别也会成为抽象类别,无法被实例化。
    • 抽象类别可以有初始化方法 (init) 吗?可以,抽象类别的初始化方法可以用于设置通用属性,并被子类别继承。

    总结

    @abstractmethod 是 Python 中用来声明抽象方法的装饰器。它强制子类别实作方法,确保程序设计的规范性和一致性。抽象基类通常用于定义接口,促进多型行为。