不够用但够轻量,因无编译期检查、无接口约束、子类未重写仅运行时崩溃;规范写法需满足:基类定义、纯raise NotImplementedError、明确签名与docstring声明、避开特殊方法。

Python里用NotImplementedError模拟虚函数,真的够用吗?
不够用,但够轻量。它不提供编译期检查、没有接口约束、子类忘记重写也不会报错——直到运行时调用才崩。但它确实是Python中最贴近“纯虚函数”语义的惯用写法,尤其适合快速原型或内部约定强的项目。
怎么写才算规范的“虚方法”?
关键不是抛异常本身,而是方法签名、文档和使用位置。必须满足三个条件:
- 定义在基类中,且只包含
raise NotImplementedError(不带任何逻辑) - 方法名和参数列表明确,最好用
:raises NotImplementedError:在 docstring 里声明 - 不能是
__init__或__del__这类特殊方法(它们被隐式调用,容易误崩)
示例:
class Shape:
def area(self) -> float:
"""计算面积,子类必须重写。"""
raise NotImplementedError("子类需实现 area() 方法")
为什么不用abc.ABC和@abstractmethod?
因为 @abstractmethod 是更严格的替代方案:它让类变成抽象基类,禁止实例化,且子类未实现会直接报 TypeError(而非运行时 NotImplementedError)。但代价是侵入性强——一旦用了 abc.ABC,就得继承 ABC,还可能触发 __subclasshook__ 等机制。如果你只是想“提醒自己别忘了重写”,NotImplementedError 更灵活;如果需要强制约束+类型检查工具(如 mypy)识别接口,就该用 @abstractmethod。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
立即学习“Python免费学习笔记(深入)”;
最容易踩的坑:忘记重写却没触发异常
常见于以下情况:
- 子类写了同名方法,但拼错了名字(比如
aread而非area) - 父类方法被意外覆盖(例如通过
setattr或 monkey patch),而你没意识到 - 调用链绕过了该方法(比如子类重写了
__str__,但里面没调self.area(),导致异常根本不会抛)
建议在测试中显式检查:isinstance(obj, BaseClass) 后再调一次该方法,确保它真抛了 NotImplementedError ——否则说明子类没按约定来。

















