python中的抽象类在项目中的实际应用
抽象类在项目中的实际应用主要体现在 规范代码结构、强制子类实现某些方法、提供部分通用功能,让代码更稳定、易维护。
举个例子:数据校验器
假设你在做一个 用户输入校验系统,需要支持 数字校验、字符串校验 和 邮箱校验。如果不用抽象类,每个校验器都会自己定义 validate() 方法,开发者可能忘了统一标准,导致代码不一致。
用抽象类改进
from abc import ABC, abstractmethodclass Validator(ABC): """抽象类:所有校验器的基类,规定必须有 validate 方法"""@abstractmethoddef validate(self, value):"""子类必须实现这个方法,否则会报错"""pass class NumberValidator(Validator): """数字校验器"""def validate(self, value):return isinstance(value, (int, float)) # 只接受数字class EmailValidator(Validator): """邮箱校验器"""def validate(self, value):return isinstance(value, str) and "@" in value # 简单的邮箱格式检查# 试试用这些校验器:
num_validator = NumberValidator()
print(num_validator.validate(123)) # True
print(num_validator.validate("abc")) # Falseemail_validator = EmailValidator()
print(email_validator.validate("test@example.com")) # True
print(email_validator.validate(123)) # False
为什么用抽象类?
-
强制所有校验器实现
validate()Validator规定了必须有validate(),如果子类忘记写,Python 会报错,避免代码不完整:
class BadValidator(Validator):pass # 忘了写 validate 方法obj = BadValidator() # TypeError: Can't instantiate abstract class BadValidator with abstract method validate -
代码更清晰,扩展更方便
- 如果以后要加 日期校验器 之类的,只需要继承
Validator并实现validate(),不会影响现有代码:
class DateValidator(Validator):def validate(self, value):return isinstance(value, str) and "-" in value # 简单日期格式检查 - 如果以后要加 日期校验器 之类的,只需要继承
-
减少重复代码,提供通用功能
- 抽象类不仅能定义“必须实现的方法”,还能提供公共方法:
class Validator(ABC):@abstractmethoddef validate(self, value):passdef is_valid(self, value):"""包装一下 validate 方法,返回 True/False"""try:return self.validate(value)except:return False
总结
- 抽象类 是“半成品”类,不能直接用,必须让子类去填充关键方法(比如
validate())。 - 强制子类实现关键方法,避免开发者忘记写,导致功能缺失。
- 让代码结构清晰,团队合作时,每个校验器都符合相同规则,方便扩展。
- 可以提供部分通用功能,减少重复代码。
举个例子:日志记录系统
假设你在开发一个日志系统,需要支持 控制台日志、文件日志 和 数据库日志。
如果不用抽象类,每个日志处理类可能命名、方法都不一样,导致代码风格混乱、调用方式不统一。
不用抽象类(混乱)
class ConsoleLogger:def log_message(self, msg):print(f"Console: {msg}")class FileLogger:def write_log(self, msg):with open("log.txt", "a") as f:f.write(f"File: {msg}\n")class DatabaseLogger:def save(self, msg):print(f"Saving '{msg}' to database...")
问题:
- 每个日志类的方法名字不一样 (
log_message()、write_log()、save()),调用时不统一。 - 如果有人写了
NetworkLogger,他可能又起个新名字,比如send_log(),代码越来越乱。
用抽象类改进
from abc import ABC, abstractmethodclass Logger(ABC):"""抽象类:所有日志类的基类"""@abstractmethoddef log(self, msg):"""子类必须实现这个方法"""pass class ConsoleLogger(Logger):"""控制台日志"""def log(self, msg):print(f"Console: {msg}")class FileLogger(Logger):"""文件日志"""def log(self, msg):with open("log.txt", "a") as f:f.write(f"File: {msg}\n")class DatabaseLogger(Logger):"""数据库日志"""def log(self, msg):print(f"Saving '{msg}' to database...")# 统一调用方式
def process_logs(logger: Logger, message: str):"""统一的日志处理逻辑"""logger.log(message)# 使用不同日志处理器
console_logger = ConsoleLogger()
file_logger = FileLogger()
db_logger = DatabaseLogger()process_logs(console_logger, "This is a console log.")
process_logs(file_logger, "This is a file log.")
process_logs(db_logger, "This is a database log.")
为什么用抽象类?
-
所有日志类的方法名保持一致
- 统一用
log(msg),不管是控制台、文件还是数据库,代码调用方式完全一样,方便维护和扩展。
- 统一用
-
强制子类实现
log()方法- 如果开发者新写
NetworkLogger但忘记实现log(),Python 会报错,防止功能缺失:
class NetworkLogger(Logger):pass # 忘了写 log 方法logger = NetworkLogger() # TypeError: Can't instantiate abstract class NetworkLogger with abstract method log - 如果开发者新写
-
新增日志方式更方便
- 以后要加 云日志、远程 API 日志 之类的,只需继承
Logger并实现log(),不会影响现有代码:
class CloudLogger(Logger):def log(self, msg):print(f"Sending '{msg}' to cloud storage...") - 以后要加 云日志、远程 API 日志 之类的,只需继承
-
提高代码可读性,减少混乱
- 团队成员看到
Logger抽象类,就知道所有日志类都有log()方法,而不会有人随便起不同的方法名。
- 团队成员看到
总结
- 抽象类 让所有日志类的接口统一,防止命名混乱。
- 强制子类实现
log()方法,防止开发者漏写关键功能。 - 以后要新增日志类型,只需要继承
Logger并实现log()方法,不影响其他代码。 - 调用方式一致,使用
process_logs(logger, msg)处理不同日志,避免各种log_message()、write_log()、save()的混乱。
在这里你可能又有一个疑问

是否可以理解成抽象类其实就是一个父类?
是的,可以理解成 “抽象类就是一个特殊的父类”,但是相比普通父类,它有以下 两点关键区别:
-
不能直接实例化(不能直接创建对象)
- 例如
Logger只是个抽象概念,不能Logger()直接用,而是用它的子类(ConsoleLogger、FileLogger)。
logger = Logger() # ❌ 报错:TypeError: Can't instantiate abstract class Logger - 例如
-
必须让子类实现某些方法
- 抽象类里用
@abstractmethod标记的方法,子类必须重写,否则 Python 不允许创建子类的实例:
class Logger(ABC):@abstractmethoddef log(self, msg):pass # 这个方法必须由子类实现 - 抽象类里用
普通父类 vs 抽象类
| 特性 | 普通父类 | 抽象类 |
|---|---|---|
| 能否直接创建对象? | ✅ 可以 | ❌ 不能 |
| 是否强制子类实现方法? | ❌ 不强制 | ✅ 强制 |
简单来说:
- 普通父类更像是可以直接用的工具箱,你可以直接拿来创建对象。
- 抽象类更像是一张设计图,告诉子类“必须实现哪些方法”,但不能直接用。
如果只是提供通用功能(比如 super().__init__() 共享构造逻辑),用普通父类就够了。
如果是设计一个必须让子类实现某些功能的模板,那就用抽象类。
你可以把抽象类想象成“公司规定”——
“所有员工(子类)都必须打卡(实现
log()方法)!”
“但是规定本身(Logger抽象类)不能当员工。”
那么我们又如何从代码上区分一个类是抽象类还是普通的父类?
从代码上区分 抽象类 和 普通父类,主要看以下几个特征:
1. 是否继承 ABC
- 抽象类 必须继承
ABC(Abstract Base Class),普通父类不需要。
from abc import ABC, abstractmethodclass AbstractClass(ABC): # ✅ 抽象类,继承 ABCpassclass NormalClass: # ❌ 普通父类,没有继承 ABCpass
2. 是否有 @abstractmethod
- 抽象类 至少有一个
@abstractmethod装饰的方法,普通父类没有。
from abc import ABC, abstractmethodclass AbstractClass(ABC):@abstractmethoddef required_method(self):pass # 这个方法必须让子类实现class NormalClass:def normal_method(self):pass # 这个方法可选,子类不一定要实现
3. 能否直接实例化
- 抽象类 不能 直接实例化,普通父类可以。
abstract_obj = AbstractClass() # ❌ TypeError: 不能实例化抽象类
normal_obj = NormalClass() # ✅ 可以实例化普通父类
4. 是否强制子类实现某些方法
- 抽象类 强制 子类必须实现
@abstractmethod方法,否则不能实例化子类。
class ConcreteClass(AbstractClass): # 继承抽象类passobj = ConcreteClass() # ❌ TypeError: 子类没实现 required_method,无法实例化
总结:快速判断方法
| 判断方法 | 普通父类 | 抽象类 |
|---|---|---|
是否继承 ABC? | ❌ 否 | ✅ 是 |
是否有 @abstractmethod? | ❌ 没有 | ✅ 有 |
| 能否直接创建对象? | ✅ 可以 | ❌ 不行 |
| 子类是否必须实现某些方法? | ❌ 不强制 | ✅ 强制 |
如果一个类符合 继承 ABC 且有 @abstractmethod,那它就是 抽象类!
否则,它就是 普通父类。
相关文章:
python中的抽象类在项目中的实际应用
抽象类在项目中的实际应用主要体现在 规范代码结构、强制子类实现某些方法、提供部分通用功能,让代码更稳定、易维护。 举个例子:数据校验器 假设你在做一个 用户输入校验系统,需要支持 数字校验、字符串校验 和 邮箱校验。如果不用抽象类&…...
New Game--(单调队列)
I - New Game 有一种新的游戏,Monocarp 想要玩。这个游戏使用一副包含 n 张牌的牌堆,其中第 i 张牌上写有一个整数 a_i。 在游戏开始时,Monocarp 可以在第一轮选择牌堆中的任意一张牌。在接下来的每一轮中,Monocarp 可以选择一张…...
mapbox V3 新特性,添加下雪效果
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象…...
无人机遥感在农林信息提取中的实现方法与GIS融合制图教程
遥感技术作为一种空间大数据手段,能够从多时、多维、多地等角度,获取大量的农情数据。数据具有面状、实时、非接触、无伤检测等显著优势,是智慧农业必须采用的重要技术之一。 一:综合态势分析 1.1 研究区及作物品种分析 ÿ…...
生物发酵展与2025生物医药创新技术与应用发展论坛同期盛大举办
近日,备受瞩目的生物发酵展与2025生物医药创新技术与应用发展论坛暨展览会宣布将同期盛大举办。这一消息标志着生物科技领域两大盛会的强强联合,将为全球生物科技与医药行业带来前所未有的交流与合作机遇。 生物发酵展作为生物科技领域的知名展会&#x…...
Jenkins 配置 Git Repository 五
Jenkins 配置 Git Repository 五 这里包含了 Freestyle project 任务类型 和 Pipeline 任务类型 关于 Git 仓库的配置,如下 不同的任务类型,只是在不同的模块找到 配置 Git 仓库 找到 Git 仓库配置位置之后,所有的任务类型配置都是一样的 …...
记录阿里云CDN配置
网站接入CDN全流程,共4步!-阿里云开发者社区 1、开通阿里云CDN服务 2、添加加速域名 3、验证域名归属权 4、域名添加CDN生成的CNAME解析 按照官网描述增加。细节点: 1. 域名和泛域名区别 2.开启https,要用nginx的证书,和项…...
mapbox 从入门到精通 - 目录
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀总目录1.1 ☘️ mapbox基础1.2 ☘️…...
mysql中general_log日志详解
介绍 1.记录范围:这个log里面会记录MySQL所有的SQL语句,不管是查询语句,还是DML语句,还是DDL语句,还是DCL语句,这些语句统统都会被记录在general log文件中。就连我们连接和断开MySQL数据库的这些语句。 2…...
算法与数据结构:从基础到深入
1. 数组 (Array) 定义 一组连续内存空间存储的相同类型元素的集合。特点:通过下标(索引)快速访问元素,但大小固定(静态数组)或可扩展(动态数组)。 核心操作 操作时间复杂度说明访…...
基于千兆5G网关的5G急救车方案
伴随5G网络的全面建成,5G技术的低延时、高速率、广接入等优势,为各行各业都带来了新一轮技术升级。在医疗救援方面,救护车是链接病患与医院的重要纽带,得益于5G物联网的融合应用,救护车也快速向联网化、信息化、智能化…...
【C#】的WPF或是WinForm实现Ctrl+ 的快捷键组合使用
在C#中,无论是WPF还是WinForms应用程序,处理快捷键(例如 Ctrl )通常涉及检测键盘输入并执行相应的命令或方法。 WPF 实现 在WPF中,可以通过设置一个控件的 InputBindings 属性来绑定快捷键。 <Window x:Class&qu…...
c语言样式主题 清爽风格 代码色彩 keil风格 适合单片机开发GD32 STM32等 cursor或者vscode 的settings.json文件
c语言样式主题 清爽风格 代码色彩 keil风格 适合单片机开发GD32 STM32等 cursor或者vscode 的settings.json文件 如上图,是不是和keil mdk很相近。 代码色彩,简单,配合 // 设置工作台主题为 Visual Studio 2017 Light - C 主题使用…...
DeepSeek API 调用 - Spring Boot 实现
DeepSeek API 调用 - Spring Boot 实现 1. 项目依赖 在 pom.xml 中添加以下依赖: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></depe…...
图数据库Neo4j面试内容整理-节点(Node)
在图数据库中,节点(Node)是图结构中的基本构建块,代表实体或对象。节点通常用于存储数据模型中的主要对象,比如人、商品、地点等。在图数据库中,节点是通过标签(Label)来分类的,并且可以包含属性(Property)来描述它们的详细信息。 1. 节点的组成<...
使用verilog 实现 cordic 算法 ----- 旋转模式
1-设计流程 ● 了解cordic 算法原理,公式,模式,伸缩因子,旋转方向等,推荐以下链接视频了解 cordic 算法。哔哩哔哩-cordic算法原理讲解 ● 用matlab 或者 c 实现一遍算法 ● 在FPGA中用 verilog 实现,注意…...
2.14寒假
这几天复习的搜索把之前做过的题目看了一下。 解析:int dx[5]{0,0,1,0,-1}; 和 int dy[5]{0,1,0,-1,0};:这两个数组用于表示上下左右四个方向的偏移量,方便在 DFS 中访问相邻的元素。o 和 p 分别表示当前搜索位置的行和列。边界条件判断&…...
基于逻辑概率的语义信道容量(Semantic Channel Capacity)和语义压缩理论(Semantic Compression Theory)
基于逻辑概率的语义信道容量(Semantic Channel Capacity)和语义压缩理论(Semantic Compression Theory)是语义通信(Semantic Communication, SemCom)的核心研究方向,它们旨在优化通信效率&#…...
DeepSeek R1本地部署教程
尽管许多卖课博主声称能轻松运行满血版DeepSeek R1,但满血版R1模型参数高达671B,仅模型文件就需要404GB存储空间,运行时更需要约1300GB显存。 对于没有卡的普通玩家来说,运行的条件苛刻,且门槛极高。基于此࿰…...
CEF132编译指南 MacOS 篇 - 获取 CEF 源码 (五)
1. 引言 在完成了所有必要工具的安装和配置之后,我们正式进入获取 CEF132 源码的阶段。对于 macOS 平台,CEF 的源码获取过程需要特别注意不同芯片架构(Intel 和 Apple Silicon)的区别以及版本管理。本篇将作为 CEF132 编译指南系…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
