当前位置: 代码网 > it编程>前端脚本>Python > 一文搞懂 Python 的 abc.ABC基类

一文搞懂 Python 的 abc.ABC基类

2026年02月04日 Python 我要评论
在 python 里,abc.abc 是“抽象基类(abstract base class)”的基类。你可以把它理解为:一个“专门用来被继承的类”,它本

在 python 里,abc.abc 是“抽象基类(abstract base class)”的基类。你可以把它理解为:

一个“专门用来被继承的类”,它本身不一定能直接用来实例化,主要作用是 规定接口、做类型约束

在日常写 python 类时,你可能见过这样的代码:

from abc import abc, abstractmethod

class animal(abc):
    @abstractmethod
    def speak(self):
        pass

这里的 abc 是什么?为什么要这么写?不写会怎样?这篇文章就来系统讲清楚:abc.abc 到底是干嘛用的、怎么用、什么时候值得用。

一、abc.abc是什么?

1. 它来自哪个模块?

abc 定义在标准库 abc 模块中:

from abc import abc

abc 全称 abstract base classes,即“抽象基类”。
abc 就是一个“抽象基类的基类”。

2. 抽象基类(abstract base class)是什么?

抽象基类(简称 abc)是用来 定义接口规范 的类,它通常具有这些特点:

  1. 不打算直接被实例化(至少设计上是这样);
  2. 定义了一些必须由子类实现的方法
  3. 在 python 中,这些“必须实现的方法”是通过 @abstractmethod(以及其他类似的装饰器)标记的。

通俗理解:

抽象基类是“接口模板”,子类是“真正干活的实现”。

二、为什么要用abc.abc?不用行不行?

先说结论:不用也“能跑”,但容易乱

1. 不用abc.abc会出现的问题

想象你写了一个“动物”类:

class animal:
    def speak(self):
        raise notimplementederror

约定所有子类都要重写 speak
问题在于:

  • 可以实例化 animal,直到你调用 speak() 才会在运行时爆出 notimplementederror
  • 没有任何机制在 类定义阶段 检查“子类到底有没有实现 speak”。

这意味着:

  • 错误暴露得晚(运行时才知道);
  • 新人接手代码时,不知道哪些方法是强制要实现的,只能靠文档或注释。

2. 使用abc.abc带来的好处

有了 abc.abc@abstractmethod

from abc import abc, abstractmethod

class animal(abc):
    @abstractmethod
    def speak(self):
        pass

好处立刻显现:

  1. 不能直接实例化抽象类

    a = animal()  # typeerror: can't instantiate abstract class animal with abstract method speak
    
  2. 子类必须实现所有抽象方法才能被实例化

    class dog(animal):
        pass
    
    dog()  # typeerror: can't instantiate abstract class dog with abstract method speak
    

    一旦子类漏实现了 speak,在你实例化它的时候就会立刻报错。

  3. 抽象方法在 ide / 文档里会有明确标记,接口规范更加清晰。

总结一下:

不用可以,但用了更安全、更清晰、更工程化。

三、abc.abc的基本用法

1. 定义抽象基类

from abc import abc, abstractmethod

class animal(abc):
    @abstractmethod
    def speak(self):
        """让动物发出叫声"""
        pass

    def sleep(self):
        """普通实例方法,可以有默认实现"""
        print("zzz...")

这里重点:

  • animal 继承了 abc,因此它是一个抽象基类;
  • speak 上加了 @abstractmethod,代表是抽象方法;
  • sleep 是普通方法,可以给出一个默认实现。

2. 定义子类并实现抽象方法

class dog(animal):
    def speak(self):
        print("woof!")

class cat(animal):
    def speak(self):
        print("meow~")

现在:

dog().speak()  # woof!
cat().sleep()  # zzz...

而如果写:

class fish(animal):
    # 没有实现 speak
    pass

fish()  # typeerror: can't instantiate abstract class fish with abstract method speak

四、抽象方法可以有方法体吗?

很多人以为“抽象方法就不能写代码”,其实这是误解。

在 python 中,抽象方法完全可以有实现:

from abc import abc, abstractmethod

class base(abc):
    @abstractmethod
    def process(self, data):
        print("base processing:", data)

子类必须重写 process,但可以通过 super() 调用父类的实现:

class child(base):
    def process(self, data):
        super().process(data)
        print("child extra processing:", data)

c = child()
c.process("hello")
# 输出:
# base processing: hello
# child extra processing: hello

所以:

@abstractmethod 的意义不是“这里不能写代码”,而是“子类必须重写这个方法”。

五、抽象属性、类方法、静态方法

abc 还提供了更多装饰器,可以和 @abstractmethod 组合使用。

1. 抽象属性

from abc import abc, abstractmethod

class shape(abc):
    @property
    @abstractmethod
    def area(self):
        """返回面积"""
        pass

子类必须实现属性 area

class circle(shape):
    def __init__(self, r):
        self.r = r

    @property
    def area(self):
        return 3.14 * self.r * self.r

如果子类不实现该属性,实例化时会报 typeerror

2. 抽象类方法 / 静态方法

from abc import abc, abstractmethod

class serializer(abc):
    @classmethod
    @abstractmethod
    def from_string(cls, s: str):
        """从字符串反序列化"""
        pass

    @staticmethod
    @abstractmethod
    def validate(data):
        """验证数据是否合法"""
        pass

子类必须实现 from_stringvalidate

class jsonserializer(serializer):
    @classmethod
    def from_string(cls, s: str):
        import json
        return json.loads(s)

    @staticmethod
    def validate(data):
        return isinstance(data, (dict, list))

六、abc与abcmeta的关系

在内部,abc 是用一个特殊的 metaclass —— abcmeta 实现的。

等价写法其实是:

from abc import abcmeta

class myabc(metaclass=abcmeta):
    ...

但日常开发中,不推荐直接用 abcmeta,而是:

from abc import abc

class myabc(abc):
    ...

因为:

  • 继承 abc 可读性更好;
  • 很多工具 / ide 都默认识别这种模式。

简单记住:

想定义抽象基类,只需要继承 abc,无需直接操作 abcmeta。

七、abc.abc在实际工程中的使用场景

场景 1:定义统一接口,屏蔽实现细节

例如设计一个消息发送系统,希望支持多种渠道(邮箱、短信、钉钉等):

from abc import abc, abstractmethod

class notifier(abc):
    @abstractmethod
    def send(self, to, message):
        """发送消息"""
        pass

各种具体实现:

class emailnotifier(notifier):
    def send(self, to, message):
        print(f"email to {to}: {message}")

class smsnotifier(notifier):
    def send(self, to, message):
        print(f"sms to {to}: {message}")

业务代码只依赖 notifier 接口:

def notify_user(notifier: notifier, user, text):
    notifier.send(user.contact, text)

其中 notifier 可以是任意符合接口的实现类。
日后需要新增一个 dingtalknotifier,只要继承 notifier 并实现 send 即可。

场景 2:插件系统或扩展点

例如你写了一个框架,想让别人“插入自己的算法”,就可以用 abc.abc 规定一个基类,让所有插件作者都按这个接口实现:

class plugin(abc):
    @abstractmethod
    def name(self) -> str:
        pass

    @abstractmethod
    def run(self, data):
        pass

框架侧逻辑:

def run_all_plugins(plugins, data):
    for p in plugins:
        print(f"running plugin: {p.name()}")
        p.run(data)

插件作者只需要按照约定继承并实现方法。
如果漏实现,就会在实例化 / 注册时直接报错,避免线上才发现错误。

场景 3:为类型检查 / ide 提供更好支持

抽象基类为 静态类型检查 提供了很好的基础:

def do_something(animal: animal):
    animal.speak()

类型检查工具(如 mypy、pyright)能够根据 animal 的定义更准确地判断类型是否匹配;ide 也能更好地做自动补全。

八、和“鸭子类型”的关系

python 一直强调“鸭子类型”:

像鸭子一样走路、像鸭子一样叫,那它就是鸭子。

按照鸭子类型哲学,你甚至不用继承任何基类,方法名对得上就可以被当成“鸭子”。

那抽象基类是不是和鸭子类型相矛盾?其实:

  • 抽象基类强调 显式的接口约束
  • 鸭子类型强调 行为匹配即可

在大型项目、多人协作中,显式约束通常更安全、更易维护
在小脚本、试验性代码中,随意一点无可厚非。

所以:

abc.abc 不是为了推翻鸭子类型,而是在需要“约束和清晰接口”的地方,给你一把更强的工具。

九、使用abc.abc的最佳实践

  1. 当你写的类“本来就是用来被继承”的时候,用 abc 明确表达意图;
  2. 所有需要子类强制实现的方法,都应该加上 @abstractmethod
  3. 抽象方法可以带默认实现,但请在 docstring 中说明子类是否需要调用 super()
  4. 不要滥用:
    • 小型脚本、一次性代码,没必要刻意引入 abc
    • 对外暴露的库、框架、长期维护的项目,强烈建议使用。

十、总结:一句话记住abc.abc

  • abc.abc 是 python 用来定义 抽象基类 的基类;
  • 你通过继承 abc + @abstractmethod 来定义“必须由子类实现”的接口;
  • 它的作用是:让接口约定更明确,让错误更早暴露,让多人协作更安全。

如果你在写库、写框架、写可复用组件,abc.abc 是值得熟练掌握的工具。

到此这篇关于一文搞懂 python 的 abc.abc基类的文章就介绍到这了,更多相关python abc.abc 内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com