面向对象基本概念:多态;附带应用例子

article/2025/8/20 9:08:56

目录

一. 多态的概念简介

二. 多态的例子一:偏好过滤器

三. 多态的例子二:审查描述符(需要元编程知识)

 四. 总结


面向对象编程(Object Oriented Programming,OOP)有三大核心概念:封装,继承,多态。前两个概念广为人知,却有很多人不清楚“多态”这个概念。下面我们就来简单谈谈多态究竟是怎么一回事。

一. 多态的概念简介

所谓多态,简单地说就是指为不同数据类型的实体提供统一的接口,而不同的类型其调用效果不同。

例如,下面的Python“动物”抽象类定义了“叫”抽象方法,这要求所有继承自动物的类必须各自实现自己的“叫”方法。依靠这种特性,当我们知道一个类型是“动物”的具体子类时,就知道它一定支持“叫”这个接口。但是,“叫”调用的结果随着具体类型的不同而不同

from abc import ABC, abstractmethodclass 动物(ABC):@abstractmethoddef 叫(self):'''动物应当会发声'''class 狗子(动物):def 叫(self):print('汪汪汪!')
class 猫咪(动物):def 叫(self):print('喵喵喵~')x = 狗子()
y = 猫咪()lst = [1, 2, x, 3 ,y]for obj in lst:if isinstance(obj, 动物):obj.叫()

在这段代码中,我们遍历许多对象,如果对方通过了针对“动物”的实例检查,我们就知道它一定有“叫”这个方法,从而放心地进行调用。行为的不同就是多态的体现:

说白了,其实多态不就是这点事吗(* ̄▽ ̄)~*,严谨的知识我会在最后给出。下面我们来看两个具体使用多态的例子,通过例子理解起来是最有效的。

二. 多态的例子一:偏好过滤器

比方说我在网上爬来了下面这样有关作品及其章节的数据(假设这是个很大的数据):

datas = [{'标题': '母猪的产后护理','来源': '《念诗之王》'},{'标题': '物理人的自我修养','来源': '《大雪牲思想道德修养》'},{'标题': '全拿来糊墙了','来源': '《念诗之王》'},{'标题': '他们朝我扔粑粑','来源': '《四川芬达》'}
]

而我对《念诗之王》这部作品情有独钟,只想从数据中提取有关它的章节。那么我可以写出下面这段代码,判断来源是不是《念诗之王》,从而决定要不要收集它:

class 数据筛选器:def __init__(self, 数据):self.数据 = 数据def 筛选数据(self):结果 = []for 项目 in self.数据:if 项目['来源'] == '《念诗之王》':结果.append(项目['标题'])return 结果我的筛选器 = 数据筛选器(datas)print(我的筛选器.筛选数据())

但是,人的激情毕竟是一阵一阵的。假设我突然改为喜欢《大雪牲思想道德修养》 这部作品了,只想收集有关它的标题,那就必须硬编码修改程序:

class 数据筛选器:def __init__(self, 数据):self.数据 = 数据def 筛选数据(self):结果 = []for 项目 in self.数据:if 项目['来源'] == '《大雪牲思想道德修养》':结果.append(项目['标题'])return 结果

每次需求改变,就必须硬性修改程序代码,这未免也太不好用了吧?

但如果我能把“筛选”的逻辑独立出来,给这个“数据筛选器”类新增一个“过滤器”属性,把检查逻辑委托给“过滤器”,那么就可以依赖过滤器的多态来适应各种情况。先顺着这个思路改写一下“数据筛选器”类:

class 数据筛选器:def __init__(self, 数据, 过滤器):self.数据 = 数据self.过滤器 = 过滤器def 筛选数据(self):结果 = []for 项目 in self.数据:if self.过滤器.要保留(项目):结果.append(项目['标题'])return 结果

这里,动态的筛选过程依赖过滤器“要保留”方法的多态。

然后,我们来具体实现过滤器,下面是完整代码清单:

from abc import ABC, abstractmethoddatas = [{'标题': '母猪的产后护理','来源': '《念诗之王》'},{'标题': '物理人的自我修养','来源': '《大雪牲思想道德修养》'},{'标题': '全拿来糊墙了','来源': '《念诗之王》'},{'标题': '他们朝我扔粑粑','来源': '《四川芬达》'}
]
# "基过滤器"是抽象基类,它的"要保留"方法依赖
# 它的抽象方法"获取保留值"
class 基过滤器(ABC): 
# 这个方法定义为抽象方法,强制要求子类必须实现@abstractmethoddef 获取保留值(self): '''子类必须声明具体保留值'''def 要保留(self, 项目): if 项目['来源'] in self.获取保留值():return Truereturn False
# 这个子类过滤器具体实现了抽象方法
class 念诗之王过滤器(基过滤器): def 获取保留值(self):return ['《念诗之王》']class 数据筛选器:def __init__(self, 数据, 过滤器):self.数据 = 数据self.过滤器 = 过滤器def 筛选数据(self):结果 = []for 项目 in self.数据:if self.过滤器.要保留(项目):结果.append(项目['标题'])return 结果# 传入子类过滤器的实例,利用它的多态性完成筛选
念诗之王筛选器 = 数据筛选器(datas, 念诗之王过滤器()) print(念诗之王筛选器.筛选数据())

像这样依赖对象的多态性实现的方案具有很强的可扩展性。例如,假设我突然想要获取《念诗之王》和《四川芬达》这两部作品的标题,只要像下面这样:

class 四川之王过滤器(基过滤器):def 获取保留值(self):return ['《念诗之王》', '《四川芬达》']四川之王筛选器 = 数据筛选器(datas, 四川之王过滤器())print(四川之王筛选器.筛选数据())

这是第一个例子。下面我们再看一个例子, 依赖子类型的多态来实现拒绝非法数据。

三. 多态的例子二:审查描述符(需要元编程知识)

在Python中,使用“三思而后行”策略编程是容易碰壁的,因为Python超强的动态特性使得全面排查非法输入繁琐而困难。要是这些审查逻辑还不能复用,那就太折磨人了!

幸好,属性描述符这个高级特性非常适合用来审查输入。下面我们直接看基类的逻辑:

from abc import ABC, abstractmethod
# 这是一个抽象基类描述符
class 审判者(ABC):
# 前两个方法都是标准实现def __set_name__(self, owner, name):self.name = namedef __get__(self, instance, name):return instance.__dict__[self.name]
# 它的设置值逻辑依赖这个抽象方法,子类必须实现。@abstractmethoddef 审判(self, value):'''审查值,如果不通过就抛出异常。'''
# 如果审判不通过就报错,让设置值无法成功。
# 如果不报错,那就能顺利设置值。def __set__(self, instance, value):self.审判(value)instance.__dict__[self.name] = value

假设我正在编写一个Person类,它需要身高和体重两个参数,这两个参数都必须是正数。那我就可以定义一个“正数审查员”具体子类:

class 正数审查员(审判者):def 审判(self, value):if not isinstance(value, (float, int)) or isinstance(value, bool):raise TypeError(f'{self.name}属性必须是正数,不能是{value.__class__.__name__}类型')if value <= 0:raise ValueError(f'{self.name}属性必须是正数,不能是{value!r}')

然后,在Person类中使用它,就可以利用“审判”的多态来拒绝非正数输入:

class Person:height = 正数审查员()weight = 正数审查员()def __init__(self, height, weight):self.height = heightself.weight = weight

传入合法参数,实例成功创建:

Person(170, 50)

传入非法参数,拒绝创建实例:

Person(-170, -50)

 以及:

Person(True, -50)

完整代码清单:

from abc import ABC, abstractmethodclass 审判者(ABC):def __set_name__(self, owner, name):self.name = namedef __get__(self, instance, name):return instance.__dict__[self.name]@abstractmethoddef 审判(self, value):'''审查值,如果不通过就抛出异常。'''def __set__(self, instance, value):self.审判(value)instance.__dict__[self.name] = value
class 正数审查员(审判者):def 审判(self, value):if not isinstance(value, (float, int)) or isinstance(value, bool):raise TypeError(f'{self.name}属性必须是正数,不能是{value.__class__.__name__}类型')if value <= 0:raise ValueError(f'{self.name}属性必须是正数,不能是{value!r}')class Person:height = 正数审查员()weight = 正数审查员()def __init__(self, height, weight):self.height = heightself.weight = weightPerson(170, 50)

 四. 总结

我本来想写更多更细的,但是突然感觉写不动了QAQ。下面来总结一下多态的知识吧。

多态(Polymorphism)是面向对象编程(OOP)的核心特性之一,其核心思想是“同一接口,多种实现”。通过多态,不同的对象对同一操作可以表现出不同的行为,从而提升代码的灵活性和可扩展性。

多态的优点:

  1. 灵活性
    • 同一接口适用于不同对象,无需为每种类型编写独立代码。
    • 例如:统一调用 animal.sound(),无论 animal 是 DogCat 还是其他动物。
  2. 可扩展性
    • 新增子类时无需修改现有代码,只需遵循接口规范。
    • 例如:新增 Bird 类并实现 sound(),无需改动调用方。
  3. 代码复用
    • 通过继承和接口抽象,减少重复代码,提高开发效率。

实现条件:

  1. 继承关系:多态通常基于类的继承或接口的实现。
  2. 方法重写:子类必须重写父类的方法(或实现接口方法)。
  3. 引用传递:父类引用(或接口引用)指向子类对象。


http://www.hkcw.cn/article/YdJdauFdRT.shtml

相关文章

Linux 串口连接乱码

用到的全部软件&#xff0c;都放在这个网盘里面了&#xff0c;自取。 链接: https://pan.baidu.com/s/1AR6Lj8FS7bokMR5IrLmsIw?pwd3dzv 提取码: 3dzv 如果链接失效了&#xff0c;关注公号&#xff1a;每日早参&#xff0c;回复&#xff1a;资源&#xff0c;即可免费获取&…

linux之web实战rsync

一、rsync简介 rsync是用于数据备份共享以及增量同步的工具&#xff0c;它可以在本地计算机与远程计算机之间&#xff0c;或者两个本地目录之间同步文件&#xff08;但不支持两台远程计算机之间的同步&#xff09;。它也可以当作文件复制工具&#xff0c;替代cp和mv命令 二、…

链表经典题目(力扣 easy)

全部题目来自力扣&#xff0c;这里只做学习的记录&#xff0c;内容中部分为AI生成&#xff0c;有不对的地方可以评论或者私信哦~~ 203. 移除链表元素 &#xff08;版本一&#xff09;虚拟头节点法 # Definition for singly-linked list. # class ListNode: # def __init_…

UFSH2024 程序化生成 笔记

这篇只是把里面涉及到的网站连接做个记录。有些网站“藏"得太深了。找了半天才找到相关连接 官方视频&#xff1a; [UFSH2024]关于程序化生成&#xff0c;我们还能做什么&#xff1f; | 周杰 徐凯鸣 腾讯IEG Global_哔哩哔哩_bilibili 官方案例资源连接&#xff1a; Vit…

openEuler安装MySql8(tar包模式)

操作系统版本&#xff1a; openEuler release 22.03 (LTS-SP4) MySql版本&#xff1a; 下载地址&#xff1a; https://dev.mysql.com/downloads/mysql/ 准备安装&#xff1a; 上传安装包&#xff1a; 把下载下来的安装包上传到服务器&#xff1a;/opt/software/mysql目录…

JSON Schema

1.JSON Schema的含义 JSON Schema 是用于验证 JSON 数据结构的强大工具&#xff0c;Schema可以理解为模式或者规则&#xff0c;可以理解为JSON中的正则表达式 2.语法 2.1 type 作用&#xff1a;约束数据类型 取值范围&#xff1a;integer&#xff0c;string&#xff0c;object&…

替代 WPS 的新思路?快速将 Word 转为图片 PDF

在这个数字化办公日益普及的时代&#xff0c;越来越多的人开始关注文档处理工具的功能与体验。当我们习惯了某些便捷操作时&#xff0c;却发现一些常用功能正逐渐变为付费项目——比如 WPS 中的一项实用功能也开始收费了。 这款工具最特别的地方在于&#xff0c;可以直接把 W…

华为OD机试真题——Boss的收入(分销网络提成计算)(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

中国批准修建最昂贵运河为何受关注 重塑交通格局引发国际热议

中国即将启动一项震惊全球的大工程——浙赣粤运河。该项目总投资3200亿元,刷新了中国运河造价纪录。这条运河北起浙江杭州,穿过江西,南至广东广州的珠江出海口,全长1237公里,其中江西境内占759公里。通过钱塘江、兰江等水系连接杭州,形成贯穿浙赣粤三省的水上通道。从交通…

广东河源24小时内连震两次 市民难眠

广东河源24小时内连震两次 市民难眠!中国地震台网正式测定,5月30日2时21分在广东河源市源城区发生3.0级地震,震源深度10公里,震中位于北纬23.72度,东经114.68度。此次地震震中5公里范围内平均海拔约52米。震中周边200公里内近5年来共发生3.0级以上地震15次,最大地震是202…

74.用户编辑功能在多次修复后仍未成功实现

在用户编辑功能在多次修复后仍未成功实现之后决定换种方法 对于后端则不需要过多修改&#xff0c;只需要修改前端即可 首先&#xff0c;在 data() 中添加新的状态&#xff1a; 用户模板部分可继续沿用之前的方法所留下来的代码 修改start、cancel、save方法 修改现有的 rege…

Void:免费且隐私友好的 AI 编码利器,挑战 Cursor 地位?

开发者圈儿里最近有点小激动&#xff0c;大家都在议论一个叫Void的开源AI代码编辑器。这家伙在GitHub上人气飙涨&#xff0c;短时间内就斩获了超过22.1k的星标&#xff0c;简直成了科技圈的新宠。它被誉为“黑马”&#xff0c;不仅因为它继承了大家都很熟悉的Visual Studio Cod…

Cadence Innvous导出GDS没有STDCELL/IO/NET/VIA问题的解决方法

Cadence Innvous导出GDS之后&#xff0c;可以重新导入Cadence Virtuoso进行查看。 1. Innovus设计完成后的GDS导出命令 导出gds命令&#xff1a; streamOut [-help] <fileName> [-attachNetProp <string>] [-dieAreaAsBoundary] [-libName <string>] [-map…

菲总统任命新国家警察总长 曾主导前总统逮捕行动

菲律宾总统马科斯选定国家警察刑事调查组组长尼古拉斯托雷出任国家警察新任总长。托雷此前主导了逮捕前总统杜特尔特的行动。菲总统执行秘书卢卡斯贝尔萨敏在马拉卡南宫记者会上宣布了这一任命。交接仪式定于6月2日举行,托雷将接替即将退休的现任总长罗梅尔马比尔。托雷成为马…

《深度搜索-R1-0528》

深度搜索-R1-0528 Paper Link &#xff08;纸质链接&#xff09;&#x1f441;️ 1. 引言 DeepSeek R1 模型进行了小版本升级&#xff0c;当前版本为 DeepSeek-R1-0528。在最新的更新中&#xff0c;DeepSeek R1 通过利用增加的计算资源并在后训练期间引入算法优化机制&#x…

男子翻女友手机才发现小丑竟是自己 女子:我们就是牌友

河南许昌,刘先生称和女友恋爱2年多,女友比自己大5岁带三个娃,相处期间两人很和睦,自己给对方还房贷,孩子都叫自己爸爸了,却意外发现她手机里还有男朋友,备注叫大哥。女方:我和刘先生就是牌友,和手机里男友的马上要结婚了,给的钱全是打牌的钱...随后,女方正牌男友来到…

Arduino 编码器

旋转编码器模块 这次我们将使用的旋转编码器为360度KY-040模块&#xff0c;工作电压: 5V&#xff0c;一圈脉冲数: 20&#xff0c;旋转编码器可通过旋转可以计数正方向和反方向转动过程中输出脉冲的次数&#xff0c;旋转计数和电位计不一样&#xff0c;这种转动计数是没有限制的…

ppt一键制作:ai自动生成PPT,便捷高效超级精美!

深夜的台灯下&#xff0c;你对着杂乱的 PPT 内容反复刷新灵感&#xff0c;鼠标在字体、配色选项间来回穿梭&#xff0c;好不容易拼凑出的页面&#xff0c;却总透着浓浓的 “廉价感”&#xff1b;汇报在即&#xff0c;逻辑混乱的大纲改了又改&#xff0c;每一页感觉合适又不搭&a…

俞敏洪骑车摔倒深夜发博:感谢关心,皮外伤

5月29日,俞敏洪在青海骑行时不慎摔倒,膝盖等处磕破出血。30日凌晨1点多,他发博报平安:29日骑车有点睡着了摔了一下,感谢广大朋友关心,皮外伤,不用担心。责任编辑:zx0002

R语言在生物群落数据统计分析与绘图中的实践应用

随着生物信息学的快速发展&#xff0c;R语言因其开源、自由、免费的特点&#xff0c;在生物群落数据分析领域得到了广泛应用。生物群落数据多样且复杂&#xff0c;涉及众多统计分析方法。本文旨在介绍R语言在生物群落数据统计分析与绘图中的实践应用&#xff0c;结合具体技术要…