必须同时继承abc.abc并用@abstractmethod装饰方法,否则子类可实例化而失去约束力;因python仅通过abcmeta元类在实例化时检查抽象方法,缺一不可。

为什么 @abstractmethod 不能单独用,必须配合 ABC 类?
直接给普通类方法加 @abstractmethod 不会报错,但完全没效果——子类不实现它也不会被拦截。Python 的抽象机制依赖类的元类(ABCMeta),只有继承 ABC 或显式设置 metaclass=ABCMeta,解释器才会在实例化时检查抽象方法是否被实现。
- 错误写法:
class Interface: @abstractmethod def method(self): pass→ 实例化成功,毫无约束 - 正确写法:
class Interface(ABC): @abstractmethod def method(self): pass - 等价写法:
class Interface(metaclass=ABCMeta): @abstractmethod def method(self): pass
@abstractmethod 方法体写 pass 还是 ...?
两者都合法,但语义不同:pass 表示“明确不提供实现”,...(Ellipsis)更常用于占位或类型提示场景。实际约束力完全一样,解释器只看装饰器和类是否为抽象基类,不读方法体内容。
- 推荐用
pass:清晰表达“此处无实现,子类必须覆盖” - 避免写具体逻辑:哪怕写了
raise NotImplementedError(),子类仍可绕过(只要不调用该方法);真正强制的是实例化检查,不是运行时调用检查 - 注意:抽象方法可以有默认实现(即带函数体),但此时子类仍可选择不重写——这属于“可选实现”,不是纯接口
如何定义真正“纯接口”(无状态、无实现、仅方法签名)?
Python 没有像 Java interface 那样的语法糖,所谓“纯接口”靠约定 + 抽象基类模拟。关键点是:不定义任何实例属性、不提供任何非抽象方法、所有方法都标 @abstractmethod。
- 禁止在抽象基类中初始化实例变量(如
self.x = 0),否则子类实例化时会执行,破坏接口纯粹性 - 避免添加非抽象的辅助方法(如
def _helper(self): ...),否则它会成为接口的一部分,且子类自动继承 - 若需共享逻辑,应抽离到独立工具函数,而非塞进接口类
- 示例:
class Drawable(ABC): @abstractmethod def draw(self) -> None: pass—— 干净、无状态、只约束行为
子类忘记实现抽象方法时,错误发生在哪一刻?
错误不是在导入模块或定义子类时抛出,而是在**首次尝试实例化该子类时**触发 TypeError。这点容易误判——静态检查(如 mypy)能提前发现,但纯 Python 运行时直到 obj = MySubclass() 才崩。
- 典型报错:
TypeError: Can't instantiate abstract class MySubclass with abstract method draw - 如果子类只继承、从不实例化(比如仅作类型注解),就不会触发检查
- 调试建议:在测试中尽早实例化子类,别等到深层调用链才暴露问题
- 注意:抽象基类本身也不能实例化,否则同样报
TypeError
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











