Python 抽象基类 ABC vs ABCMeta:什么时候用哪个?
副标题 / 摘要 ABC 用来“写抽象接口并阻止未实现的类被实例化”;ABCMeta 用来“在创建类时施加规则(自动注入、校验、注册)”。本文用最短可运行例子帮你在两者之间做选择。 目标读者 Python 初学者:了解抽象类怎么用、为啥会报 TypeError 中级开发者:在“接口约束”和“元类自动化”之间做取舍 需要做插件/框架能力的人:统一约束子类结构、自动补齐类级属性 背景 / 动机 你可能遇到过这些痛点: 想规定“子类必须实现某些方法”,但团队里总有人忘写 想让一批子类都有统一的类属性(比如 plugin_name),不想每个子类手写一遍 看到别人写 metaclass=ABCMeta,不确定是不是“更高级/更正确” 结论先说:大多数业务代码只需要 ABC;只有当你真的需要“类创建期的自动化规则”时,才考虑直接使用 ABCMeta(或在它上面做扩展)。 核心概念 1)抽象方法(@abstractmethod) 被标记为抽象的方法/属性,表示“必须由子类提供实现”。只要类里还有抽象成员未实现,它就不能被实例化。 2)抽象基类(ABC, Abstract Base Class) 用于定义一组接口约束:能继承、能被 isinstance/issubclass 判断,并能阻止不完整实现的类被实例化。 3)元类(metaclass) 普通类的“类”是 type;元类决定“类是怎么被创建出来的”。你可以在元类里: 在类创建时自动添加/修改类属性 校验子类是否符合规则(命名、属性、方法签名等) 统一注册子类到某个 registry ABCMeta 就是 abc 模块提供的元类:它把“抽象基类能力”实现为一套类创建/实例化规则。 实践指南 / 步骤 步骤 1:只需要“接口约束”——用 ABC 如果你只关心“子类必须实现哪些方法”,直接继承 ABC 是最简洁的写法。 步骤 2:需要“类创建期自动化规则”——用(或继承)ABCMeta 当你希望“子类不用手写,也能按规则自动拥有某些类属性/被校验/被注册”,再考虑元类。 可运行示例 示例 A:用 ABC 做接口约束(推荐默认选项) from abc import ABC, abstractmethod class Repo(ABC): @abstractmethod def save(self, obj) -> None: ... class MemoryRepo(Repo): def save(self, obj) -> None: print("saved:", obj) # Repo() # 取消注释会抛 TypeError:抽象类不能实例化 MemoryRepo().save({"id": 1}) 你得到的是:强约束(没实现抽象方法就不能实例化),且写法清晰。 ...