应使用 abc.ABC + @abstractmethod 替代手写 raise NotImplementedError(),因其能在实例化时强制检查抽象方法实现,避免运行时才报错;NotImplementedError 仅用于标记子类必须覆盖的方法,不可作通用占位符或平台不支持提示。

为什么不能直接 raise NotImplementedError() 作为接口占位?
直接在基类方法里写 raise NotImplementedError() 看似简洁,但会导致调用栈不清晰、错误信息空泛,且无法区分“未实现”和“故意不支持”。比如子类忘记重写时,报错只显示 NotImplementedError,没提示具体哪个方法、属于哪个类。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 在
NotImplementedError构造时传入明确的提示字符串,例如raise NotImplementedError("subclasses must implement .serialize()") - 避免在
__init__或属性访问中抛出该异常——这会让实例化或属性读取失败,掩盖真正的设计意图 - 不要把它当“TODO标记”混在业务逻辑里;它只应出现在抽象契约位置(如抽象基类的纯虚方法)
如何用 abc.ABC + @abstractmethod 替代手写 raise?
手写 raise NotImplementedError() 是旧式做法,容易漏检、难约束。Python 的 abc 模块提供更严格的契约机制:子类若未实现被 @abstractmethod 标记的方法,连实例化都会失败,而不是等到运行时才报错。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 继承
abc.ABC,而非普通object;用@abc.abstractmethod装饰必须实现的方法 - 如果某方法允许子类选择性实现,就别标
@abstractmethod,改用文档说明或类型注解(如Optional[Callable]) -
abc不阻止你同时在抽象方法体里raise NotImplementedError()——这是冗余的,删掉
from abc import ABC, abstractmethod <p>class Serializer(ABC): @abstractmethod def serialize(self, data) -> str: pass # 不要在这里 raise NotImplementedError
什么时候该用 NotImplementedError 而不是其他异常?
NotImplementedError 专用于“当前类本应由子类覆盖,但此处未覆盖”的场景。它不是通用的“功能暂未开发”占位符。混淆使用会误导调用方,也破坏 Liskov 替换原则。
常见误用与修正:
- 想表示“此平台不支持该操作” → 改用
RuntimeError或自定义异常(如PlatformNotSupportedError) - 想表示“输入类型不被接受” → 应该是
TypeError或ValueError - 在协议(Protocol)中声明方法时,
NotImplementedError无意义——协议不强制实现,也不运行时检查
测试时如何验证子类确实实现了抽象方法?
光靠 abc 的实例化检查还不够:如果子类只是把抽象方法重写成 pass 或又 raise NotImplementedError(),运行时仍会崩。得在单元测试里主动调用并捕获异常。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 对每个抽象方法,写一个最小测试用例,调用它并断言不抛
NotImplementedError - 避免只测“能实例化”,要测“能执行”——例如
assert isinstance(s, Serializer)不够,还得s.serialize({}) - 可以用
inspect.getmembers(cls, predicate=inspect.isfunction)辅助检查方法是否非空实现,但注意装饰器可能干扰判断
抽象方法的边界很窄:它只回答“这个类承诺提供什么接口”,不负责解释“为什么没实现”或“怎么实现最好”。越试图用 NotImplementedError 承担额外语义,越容易让下游开发者困惑。


















