ABC类不能被直接实例化,因为继承abc.ABC或使用@abstractmethod装饰后,Python在__new__阶段检查未实现的抽象方法并抛出TypeError,实现需有实际逻辑而非仅pass,且@abstractmethod仅支持实例方法和静态方法。

Python 的 abc 模块不是“必须用”,但一旦你发现子类总在漏实现某个关键接口,或者想提前拦截不合规的实例化,它就是最轻量、最标准的解决方案。
为什么 ABC 类不能被直接实例化?
因为 ABC 类继承自 abc.ABC(或用 @abc.abstractmethod 装饰方法)后,Python 会在 __new__ 阶段检查:如果类中仍有未被重写的抽象方法,就抛出 TypeError: Can't instantiate abstract class ... with abstract method ...。
这不是语法糖,是运行时强制约束——哪怕你只忘了重写一个 save() 方法,实例化就会失败,而不是等到调用时才报错。
常见错误现象:
- 明明写了子类,却仍报 TypeError → 检查是否拼错了抽象方法名,或没加 self 参数
- 子类里用了 def save(self): pass 但依然报错 → pass 不算实现,必须有实际逻辑或至少返回值/语句(哪怕只是 return None)
@abstractmethod 必须装饰在方法上,不能装饰属性或类方法?
严格来说,@abstractmethod 只能用于实例方法和静态方法(@staticmethod + @abstractmethod),不能直接用于 @classmethod 或属性(@property)。但你可以绕过限制:
立即学习“Python免费学习笔记(深入)”;
- 类方法要抽象?先定义普通抽象方法,让子类在类方法里调用它
- 属性要强制?把
@property拆成get_foo()和set_foo()两个抽象方法,或用@abstractmethod装饰一个返回property的类方法(不推荐,可读性差) - 真正需要抽象属性?Python 3.9+ 支持
@classmethod+@abstractmethod组合,但解释器不校验,靠文档和约定
示例:
from abc import ABC, abstractmethod
<p>class DataProcessor(ABC):
@abstractmethod
def process(self, data):
pass</p><pre class="brush:php;toolbar:false;">@staticmethod
@abstractmethod
def validate_format(fmt):
pass
抽象基类和 isinstance() / issubclass() 的关系
abc.ABC 的核心价值之一是让类型检查更可靠。普通父类无法阻止用户用 isinstance(obj, Parent) 判断鸭子类型是否“符合预期”,而 ABC 可以注册虚拟子类(register())或通过继承显式声明契约。
使用场景:
- 你想让第三方类(比如
requests.Response)被当作某种协议类型 → 用MyProtocol.register(requests.Response) - 你写框架,希望用户传入的对象满足
read()和close()→ 定义Readable抽象基类,然后用isinstance(obj, Readable)做运行时检查 - 注意:
register()不会触发方法检查,只影响类型判断;真要校验行为,还得靠抽象方法本身
性能影响极小,isinstance() 对 ABC 的检查和普通类几乎无差别,但多了额外一层协议语义。
别把 abc 当成接口定义工具来滥用
Python 本就不靠类型系统约束行为,abc 是给“明确需要提前报错”的场景用的。容易踩的坑:
- 为每个小函数都建一个
ABC→ 接口爆炸,维护成本陡增 - 在数据类(
@dataclass)里混用@abstractmethod→__init__生成逻辑和抽象方法冲突,可能引发意外的TypeError - 误以为
ABC能替代文档或测试 → 它只管“有没有实现”,不管“实现得对不对”
真正该用的时候,往往是你已经看到三次同类 bug:某子类忘了实现 serialize(),结果上线后 JSON 输出为空。


















