网站首页 > 技术文章 正文
作者:麦叔
来源:麦叔编程
ABC是什么
我们来聊一个Python进阶话题,抽象基类,英文是Abstract Base Class,简称为ABC。
这个名字看起来很简单,ABC,但其实是Python进阶的重要知识点。提高Python设计能力的重要武器!
虽然Python相对Java等相对比较灵活。但要设计稍微复杂点的系统,高水平的设计者还是会使用一些设计技巧,比如使用ABC。至少Python内置集合类就大量使用了ABC。
简单来说,ABC是一种抽象的类,它只是规定了一些规范。要实现这个ABC的子类必须提供规范中要求的方法和属性。
我们来看例子吧。
设计场景
假设我们要开发一个媒体播放器。它可以播放不同的媒体格式。
在这种情况下,一个很好的选择就是创建一个ABC来声明子类需要提供的方法和属性。
一般的设计是这样的,让多个类都实现一个通用的函数,比如 play()。我们将媒体播放器定义为抽象类。每种特定的媒体文件格式(如mp4,MOV,AVI等)都可以提供抽象类的具体实现。
抽象类
下面是一个抽象类,它需要子类提供具体的方法实现和属性:
class MediaLoader(abc.ABC):
@abc.abstractmethod
def play(self) -> None:
...
@property
@abc.abstractmethod
def ext(self) -> str:
...
abc.ABC是一个用于控制实体类创建的元类。Python的默认元类是type。默认的元类当创建实例的时候不会检查抽象方法。abc.ABC扩展了type,它会阻止我们为没有被完全实现的类创建实例。
抽象方法
抽象类中有两处使用了装饰器。一处使用@abc.abstractmethod ,另一处同时使用了@property和@abc.abstractmethod。Python广泛使用装饰器来修改函数或方法的功能。在这个例子中,它为元类ABC提供了额外的细节。因为我们标注了某个方法或属性是抽象的,子类必须实现相应的方法或属性才能成为有用的、可以被实例化的类。
抽象类的方法体是**...**。这个三点标记,即省略号,确实是合法的Python 代码,用以提醒我们:具体的子类需要实现相应的方法。
抽象属性
我们在ext()方法上也使用了@property装饰器。我们的目的是为了提供一个名为ext的字符串类型的类变量。使用@property把它声明为属性,这样子类可以选择使用简单的变量或者使用方法来实现这个属性。在实体类中使用简单变量可以满足抽象类的要求,也能通过mypy的类型检查。如果需要一些更复杂的计算,可以使用方法来替代简单的属性变量。
使用了这些标记的类会拥有了一个特殊的属性__abstractmethods__。这个属性会列出所有的抽象方法或属性:
>>> MediaLoader.__abstractmethods__
frozenset({'ext', 'play'})
测试一下
如果实现一个子类,会发生什么?我们看两个例子,一个反面例子Wav,它没有为抽象提供必要的实现。一个正面例子,它为抽象提供了具体实现。
>>> class Wav(MediaLoader):
... pass
...
>>> x = Wav()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Wav with abstract methods ext, play
>>> class Ogg(MediaLoader):
... ext = '.ogg'
... def play(self):
... pass
...
>>> o = Ogg()
子类Wav没有实现任何抽象方法。当我们尝试创建一个Wav类的实例时,抛出了异常。因为作为MediaLoader的子类,它没有实现ABC要求的规范,不能创建实例。
而子类Ogg提供了抽象属性的实现,所以它可以被实例化。
在创建复杂的应用时,这有明显的优势。像这样使用抽象类,可以确保子类符合规范,也可以让mypy很清楚地判断一个类是否实现了必要的方法和属性,在开发过程中为我们实时指出问题。
ABC你懂了吗?好啦,今天就聊到这里。如果喜欢,记得点赞!
CDA数据分析师分享案例,欢迎大家留言分享你的建议。
猜你喜欢
- 2025-06-23 Python最常见的170道面试题全解析答案(二)
- 2025-06-23 python学习——034类的属性可以是其他类的实例吗?
- 2025-06-23 Python类中的self到底是干啥的(python类里面的self)
- 2025-06-23 Python面向对象编程入门指南:从零开始理解类与对象
- 2025-06-23 Python魔法函数(特殊函数)(python中魔术方法)
- 2025-06-23 一文读懂Python字段和属性(python中的属性)
- 2025-06-23 2025年AI工程师必知的15个Python库
- 2025-06-23 Python 属性界的 “双胞胎”:类属性 vs 实例属性,教你一眼辨明
- 2025-06-23 Python的实例属性和类属性(python类中属性)
- 2025-06-23 定义类和实例化对象概念及语法(定义类和实例化对象概念及语法关系)
- 06-24Python调用Docker API的使用方式(pycharm docker 调试)
- 06-24青少年Python编程系列28:Python中函数的递归调用
- 06-24python调用sqlite数据库案例(python 调用数据库)
- 06-24【Python机器学习系列】基于Flask来构建API调用机器学习模型服务
- 06-24通过pybind11来实现python调用C++接口(一)
- 06-24Python编程调用Deepseek API创建智能体
- 06-24python多装饰器针对函数、类、方法的调用顺序说明
- 06-24Python Qt GUI设计:Python调用UI文件的两种方法(基础篇—3)
- 270℃Python短文,Python中的嵌套条件语句(六)
- 268℃python笔记:for循环嵌套。end=""的作用,图形打印
- 266℃PythonNet:实现Python与.Net代码相互调用!
- 262℃Python实现字符串小写转大写并写入文件
- 261℃Python操作Sqlserver数据库(多库同时异步执行:增删改查)
- 121℃原来2025是完美的平方年,一起探索六种平方的算吧
- 101℃Python 和 JavaScript 终于联姻了!PythonMonkey 要火?
- 95℃Ollama v0.4.5-v0.4.7 更新集合:Ollama Python 库改进、新模型支持
- 最近发表
-
- Python调用Docker API的使用方式(pycharm docker 调试)
- 青少年Python编程系列28:Python中函数的递归调用
- python调用sqlite数据库案例(python 调用数据库)
- 【Python机器学习系列】基于Flask来构建API调用机器学习模型服务
- 通过pybind11来实现python调用C++接口(一)
- Python编程调用Deepseek API创建智能体
- python多装饰器针对函数、类、方法的调用顺序说明
- Python Qt GUI设计:Python调用UI文件的两种方法(基础篇—3)
- Python | Django 外部脚本调用 models 数据库
- 自学Python第九天——操作列表(python操作步骤)
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)