You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python抽象方法显式抛NotImplementedError的差异与最佳实践探讨

关于Python抽象方法两种实现形式的疑问与解答

我在研究Python内置库numbers.py的源码时,发现被@abstractmethod装饰的方法存在两种实现形式:一种没有显式抛出NotImplementedError,另一种则显式抛出。

父类示例代码

from abc import ABC, abstractmethod

class Complex(ABC):
    @abstractmethod
    def __complex__(self):
        """Return a builtin complex instance. Called for complex(self)."""

    @abstractmethod
    def __neg__(self):
        """-self"""
        raise NotImplementedError

子类实现代码

class MyComplex(Complex):
    def __complex__(self):
        return complex(1, 1)
    
    def __neg__(self):
        return complex(-1, -1)

测试结果

>>> c = MyComplex()
>>> Complex.__complex__(c)
>>> Complex.__neg__(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/maskalev/dev/foo/bar.py", line 15, in __neg__
    raise NotImplementedError
NotImplementedError

测试后发现:直接调用父类的Complex.__complex__(c)会返回None,而调用Complex.__neg__(c)则会抛出NotImplementedError。


问题1:这是唯一差异吗?

是的,这是最直观的差异,但核心逻辑上两种写法都是为了标记方法为抽象方法,强制子类必须实现。唯一的行为区别仅出现在绕开子类实现直接调用父类抽象方法时:

  • 无显式抛出的抽象方法:执行后默认返回None(Python函数无return语句时的默认行为)
  • 显式抛出的抽象方法:执行后直接抛出NotImplementedError

当子类正常实现方法后,子类实例的方法调用行为完全一致,不会有任何区别。

问题2:为何两种写法并存,不统一实现?

这是Python标准库历史演进和代码风格遗留的结果:

  • 早期抽象类实践:在abc模块完善前,开发者习惯通过显式抛出NotImplementedError标记抽象方法,这种写法被保留到了部分老代码中。
  • 特殊方法的约定差异:像__complex__这类特殊方法,Python内置逻辑对未实现的情况有明确的 fallback 处理;而__neg__这类运算符重载方法没有默认 fallback,显式抛出异常能更清晰地提示“该方法必须被子类实现”。
  • 兼容性要求:标准库需要保持向后兼容,不能随意修改已有代码的写法,因此两种形式会长期并存。

问题3:最佳实践是什么?

推荐显式抛出NotImplementedError,理由如下:

  1. 行为明确:直接调用父类抽象方法时,抛出异常能立刻提醒调用者“此方法不应直接调用,必须由子类实现”,比返回None更直观。
  2. 调试友好:调试时,异常能快速定位到未正确实现的抽象方法,而返回None可能导致后续代码出现难以排查的逻辑错误。
  3. 风格统一:统一的写法能提升代码可读性,避免团队成员对抽象方法的行为产生困惑。

少数例外场景:如果是定义__str__、__complex__这类特殊方法,且Python内置逻辑已对未实现情况有明确处理,也可以选择不写显式抛出,但这种情况占比极低。


内容的提问来源于stack exchange,提问作者maskalev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:53:11