1. 什么是抽象类? #
- 抽象类定义一组子类必须实现的方法,本身不提供完整实现,相当于"接口契约"。
- 如果子类遗漏了某个抽象方法,实例化时会立刻抛出
TypeError,而不是运行到一半才发现。
- 没有抽象类时,父类方法用
pass 占位,子类忘记重写也不会报错,容易埋隐患。
- 项目中常用于插件接口、策略模式、框架扩展点等需要"强制实现"的场景。
1.1 没有抽象类的问题 #
class Animal:
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
dog = Dog()
print(dog.move())
1.2 使用抽象类后 #
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
@abstractmethod
def move(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
def move(self):
return "Running"
2. 前置知识 #
- 使用 abc 需要了解面向对象中的类、继承和方法重写基础。
@abstractmethod 是装饰器,用法与 @property、@classmethod 类似,用 @ 标记。
- 抽象类是父类,具体实现由子类完成,子类通过继承获得父类的非抽象方法。
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def bark(self):
return f"{self.name} says Woof!"
dog = Dog("旺财")
print(dog.bark())
3. abc 模块 #
abc 是 Python 标准库,全称 Abstract Base Classes(抽象基类)。
- 核心组件只有两个:
ABC(抽象基类)和 abstractmethod(抽象方法装饰器)。
- 定义抽象类:继承
ABC,用 @abstractmethod 标记必须由子类实现的方法。
- 抽象类不能直接实例化,只有实现了所有抽象方法的子类才能创建对象。
from abc import ABC, abstractmethod
4. 基本用法 #
- 继承
ABC 并将需要子类实现的方法加上 @abstractmethod。
- 抽象方法体通常写
pass,也可以写 ...(省略号)。
- 子类必须实现所有抽象方法,否则
TypeError: Can't instantiate abstract class ...。
- 非抽象方法可以有默认实现,子类可直接使用或选择重写。
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
"""子类必须实现"""
pass
def sleep(self):
"""普通方法,有默认实现"""
return "正在睡觉..."
class Dog(Animal):
def make_sound(self):
return "Woof!"
dog = Dog()
print(dog.make_sound())
print(dog.sleep())
5. 抽象方法实战:图形系统 #
- 抽象方法适合定义"所有子类都必须提供"的核心行为,如计算面积、执行保存等。
- 父类可提供调用抽象方法的普通方法,子类只需实现抽象部分。
- 下面示例中
Shape 规定 area() 和 perimeter(),矩形和圆形各自实现。
- 这是项目中最典型的 abc 用法:定义统一接口,多种实现可互换。
from abc import ABC, abstractmethod
import math
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
@abstractmethod
def perimeter(self) -> float:
pass
def describe(self) -> str:
return f"面积: {self.area():.2f}"
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return math.pi * self.radius ** 2
def perimeter(self) -> float:
return 2 * math.pi * self.radius
rect = Rectangle(5, 3)
print(rect.describe())
6. 抽象属性 #
- 抽象属性用
@property + @abstractmethod 组合定义,子类必须实现对应的 property。
- 装饰器顺序很重要:
@property 必须在 @abstractmethod 之前。
- 典型场景:规定子类必须提供
name、version 等只读属性。
from abc import ABC, abstractmethod
class Plugin(ABC):
@property
@abstractmethod
def name(self) -> str:
pass
class JSONPlugin(Plugin):
@property
def name(self) -> str:
return "json"
7. 实际应用:策略模式 #
- 策略模式是 abc 最常见的应用场景:定义统一接口,运行时切换不同实现。
- 支付、通知、存储等"多种实现、同一调用方式"的业务都适合用抽象基类。
- 调用方依赖抽象类而非具体子类,新增实现只需继承基类,无需修改调用代码。
- 下面示例定义
PaymentStrategy,信用卡和支付宝各自实现 pay() 方法。
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float) -> bool:
pass
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number: str):
self.card_number = card_number
def pay(self, amount: float) -> bool:
print(f"信用卡 {self.card_number[-4:]} 支付 ${amount}")
return True
class AlipayPayment(PaymentStrategy):
def __init__(self, account: str):
self.account = account
def pay(self, amount: float) -> bool:
print(f"支付宝 {self.account} 支付 ${amount}")
return True
class Checkout:
def __init__(self, strategy: PaymentStrategy):
self.strategy = strategy
def pay(self, amount: float) -> bool:
return self.strategy.pay(amount)
checkout = Checkout(CreditCardPayment("1234567890123456"))
checkout.pay(99.99)
checkout = Checkout(AlipayPayment("user@example.com"))
checkout.pay(99.99)
8. 常见错误 #
- 子类未实现全部抽象方法时,实例化报
TypeError,检查报错信息中列出的方法名即可定位。
- 抽象属性装饰器顺序写反(
@abstractmethod 在 @property 前)会导致定义失败。
- 不能直接实例化抽象类本身,必须通过实现了所有抽象方法的子类创建对象。
- 不要把所有方法都设为抽象,只有真正必须实现的核心方法才需要
@abstractmethod。
8.1 忘记实现抽象方法 #
class Dog(Animal):
pass
8.2 装饰器顺序错误 #
@abstractmethod
@property
def name(self): ...
@property
@abstractmethod
def name(self): ...
8.3 直接实例化抽象类 #
9. 总结 #
- abc 模块通过
ABC + @abstractmethod 强制子类实现约定接口,避免遗漏方法。
- 项目中最常用的模式:定义抽象基类 → 多个子类实现 → 调用方依赖基类类型(策略模式)。
- 抽象方法优先于抽象属性;抽象类方法和静态方法日常较少使用,需要时再查文档。
- 只在确实需要"强制实现"时使用抽象类,简单继承关系用普通类即可。
9.1 关键写法 #
from abc import ABC, abstractmethod
class Base(ABC):
@abstractmethod
def do_work(self):
pass
class Impl(Base):
def do_work(self):
return "done"
9.2 最佳实践 #
- 只将必须实现的方法标为
@abstractmethod,其余提供默认实现
- 为抽象方法写清晰的 docstring,说明子类应如何实现
- 调用方参数类型标注为抽象基类,如
strategy: PaymentStrategy
- 用
isinstance(obj, BaseClass) 做类型检查,确保对象符合接口
9.3 适用与不适用 #
| 适合 |
不适合 |
| 插件/策略接口 |
简单父子继承 |
| 框架扩展点 |
不需要强制实现的方法 |
| 多实现可互换 |
只有一个实现的场景 |