天空大作战
94.86M · 2026-02-04
在 Python 里,abc.ABC 是“抽象基类(Abstract Base Class)”的基类。你可以把它理解为:
abc.ABC:从概念到实战在日常写 Python 类时,你可能见过这样的代码:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
这里的 ABC 是什么?为什么要这么写?不写会怎样?这篇文章就来系统讲清楚:abc.ABC 到底是干嘛用的、怎么用、什么时候值得用。
abc.ABC 是什么?ABC 定义在标准库 abc 模块中:
from abc import ABC
abc 全称 Abstract Base Classes,即“抽象基类”。
ABC 就是一个“抽象基类的基类”。
抽象基类(简称 ABC)是用来 定义接口规范 的类,它通常具有这些特点:
@abstractmethod(以及其他类似的装饰器)标记的。通俗理解:
abc.ABC?不用行不行?先说结论:不用也“能跑”,但容易乱。
abc.ABC 会出现的问题想象你写了一个“动物”类:
class Animal:
def speak(self):
raise NotImplementedError
约定所有子类都要重写 speak。
问题在于:
Animal,直到你调用 speak() 才会在运行时爆出 NotImplementedError;speak”。这意味着:
abc.ABC 带来的好处有了 abc.ABC 和 @abstractmethod:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
好处立刻显现:
不能直接实例化抽象类
a = Animal() # TypeError: Can't instantiate abstract class Animal with abstract method speak
子类必须实现所有抽象方法才能被实例化
class Dog(Animal):
pass
Dog() # TypeError: Can't instantiate abstract class Dog with abstract method speak
一旦子类漏实现了 speak,在你实例化它的时候就会立刻报错。
抽象方法在 IDE / 文档里会有明确标记,接口规范更加清晰。
总结一下:
abc.ABC 的基本用法from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
"""让动物发出叫声"""
pass
def sleep(self):
"""普通实例方法,可以有默认实现"""
print("Zzz...")
这里重点:
Animal 继承了 ABC,因此它是一个抽象基类;speak 上加了 @abstractmethod,代表是抽象方法;sleep 是普通方法,可以给出一个默认实现。class Dog(Animal):
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow~")
现在:
Dog().speak() # Woof!
Cat().sleep() # Zzz...
而如果写:
class Fish(Animal):
# 没有实现 speak
pass
Fish() # TypeError: Can't instantiate abstract class Fish with abstract method speak
很多人以为“抽象方法就不能写代码”,其实这是误解。
在 Python 中,抽象方法完全可以有实现:
from abc import ABC, abstractmethod
class Base(ABC):
@abstractmethod
def process(self, data):
print("Base processing:", data)
子类必须重写 process,但可以通过 super() 调用父类的实现:
class Child(Base):
def process(self, data):
super().process(data)
print("Child extra processing:", data)
c = Child()
c.process("hello")
# 输出:
# Base processing: hello
# Child extra processing: hello
所以:
abc 还提供了更多装饰器,可以和 @abstractmethod 组合使用。
from abc import ABC, abstractmethod
class Shape(ABC):
@property
@abstractmethod
def area(self):
"""返回面积"""
pass
子类必须实现属性 area:
class Circle(Shape):
def __init__(self, r):
self.r = r
@property
def area(self):
return 3.14 * self.r * self.r
如果子类不实现该属性,实例化时会报 TypeError。
from abc import ABC, abstractmethod
class Serializer(ABC):
@classmethod
@abstractmethod
def from_string(cls, s: str):
"""从字符串反序列化"""
pass
@staticmethod
@abstractmethod
def validate(data):
"""验证数据是否合法"""
pass
子类必须实现 from_string 和 validate:
class JsonSerializer(Serializer):
@classmethod
def from_string(cls, s: str):
import json
return json.loads(s)
@staticmethod
def validate(data):
return isinstance(data, (dict, list))
ABC 与 ABCMeta 的关系在内部,ABC 是用一个特殊的 metaclass —— ABCMeta 实现的。
等价写法其实是:
from abc import ABCMeta
class MyABC(metaclass=ABCMeta):
...
但日常开发中,不推荐直接用 ABCMeta,而是:
from abc import ABC
class MyABC(ABC):
...
因为:
ABC 可读性更好;简单记住:
abc.ABC 在实际工程中的使用场景例如设计一个消息发送系统,希望支持多种渠道(邮箱、短信、钉钉等):
from abc import ABC, abstractmethod
class Notifier(ABC):
@abstractmethod
def send(self, to, message):
"""发送消息"""
pass
各种具体实现:
class EmailNotifier(Notifier):
def send(self, to, message):
print(f"Email to {to}: {message}")
class SMSNotifier(Notifier):
def send(self, to, message):
print(f"SMS to {to}: {message}")
业务代码只依赖 Notifier 接口:
def notify_user(notifier: Notifier, user, text):
notifier.send(user.contact, text)
其中 notifier 可以是任意符合接口的实现类。
日后需要新增一个 DingTalkNotifier,只要继承 Notifier 并实现 send 即可。
例如你写了一个框架,想让别人“插入自己的算法”,就可以用 abc.ABC 规定一个基类,让所有插件作者都按这个接口实现:
class Plugin(ABC):
@abstractmethod
def name(self) -> str:
pass
@abstractmethod
def run(self, data):
pass
框架侧逻辑:
def run_all_plugins(plugins, data):
for p in plugins:
print(f"Running plugin: {p.name()}")
p.run(data)
插件作者只需要按照约定继承并实现方法。
如果漏实现,就会在实例化 / 注册时直接报错,避免线上才发现错误。
抽象基类为 静态类型检查 提供了很好的基础:
def do_something(animal: Animal):
animal.speak()
类型检查工具(如 mypy、pyright)能够根据 Animal 的定义更准确地判断类型是否匹配;IDE 也能更好地做自动补全。
Python 一直强调“鸭子类型”:
按照鸭子类型哲学,你甚至不用继承任何基类,方法名对得上就可以被当成“鸭子”。
那抽象基类是不是和鸭子类型相矛盾?其实:
在大型项目、多人协作中,显式约束通常更安全、更易维护;
在小脚本、试验性代码中,随意一点无可厚非。
所以:
abc.ABC 的最佳实践ABC 明确表达意图;@abstractmethod;super();ABC;abc.ABCabc.ABC 是 Python 用来定义 抽象基类 的基类;ABC + @abstractmethod 来定义“必须由子类实现”的接口;如果你在写库、写框架、写可复用组件,abc.ABC 是值得熟练掌握的工具。