【Python单点知识】深入理解与应用类多态

文章目录

      • 0. 前言
      • 1. 多态类的概念
      • 2. Python中实现多态类的途径
        • 2.1 类的继承
        • 2.2 抽象基类
        • 2.3 duck typing
      • 3. 多态类的应用场景
      • 4. 结论

0. 前言

按照国际惯例,首先声明:本文只是我自己学习的理解,虽然参考了他人的宝贵见解及成果,但是内容可能存在不准确的地方。如果发现文中错误,希望批评指正,共同进步。

本文介绍Python中的类的特征之一——多态性,核心是介绍多态类的实现途径。

在面向对象编程(OOP)中,多态是三大核心特性之一,与封装继承并列。它赋予了程序更高的灵活性、可扩展性和可维护性。Python作为一门支持全面OOP特性的高级语言,其对多态的支持尤为出色。本文将详细介绍Python中多态类的概念、实现方式以及实际应用场景,旨在帮助读者深入理解并有效运用Python多态类。

1. 多态类的概念

多态,简单来说,是指同一操作作用于不同对象时,可以产生不同的行为。在Python中,这种“同一操作”通常表现为方法调用,而“不同对象”则指代具有相同接口(即方法名)但具体实现各异的类实例。多态的核心价值在于,它允许程序员以统一的方式处理多种数据类型,无需关注具体的类型细节,从而提升代码的抽象层次和复用性。

2. Python中实现多态类的途径

2.1 类的继承

这是实现多态最直接的方式。子类通过继承父类并重写其部分或全部方法,使得相同的方法名在不同子类中表现出不同的行为。例如:

class Animal:def make_sound(self):passclass Dog(Animal):def make_sound(self):return "Woof!"class Cat(Animal):def make_sound(self):return "Meow!"dog = Dog()
cat = Cat()print(dog.make_sound())  # 输出: Woof!
print(cat.make_sound())  # 输出: Meow!

在这个例子中,DogCat类都继承自Animal类并重写了make_sound方法,实现了多态。尽管调用的是同名方法,但由于对象类型不同,实际执行的行为也各异。

2.2 抽象基类

Python提供了abc(Abstract Base Classes)模块来定义抽象基类,这些类包含抽象方法(未实现的方法),要求其子类必须实现这些方法。这为多态提供了一种形式化的约束机制。例如:

import abcclass Shape(metaclass=abc.ABCMeta):@abc.abstractmethoddef area(self):passclass Circle(Shape):def __init__(self, radius):self.radius = radiusdef area(self):return 3.14 * (self.radius ** 2)circle = Circle(10)
print(circle.area())  # 输出: 314

在此例中,Shape是一个抽象基类,定义了抽象方法areaCircle类继承自Shape并实现了area方法,从而成为一个具体的多态类。

2.3 duck typing

Duck Typing(鸭子类型)是Python编程语言中的一种动态类型特征,源自一句著名的说法:“If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.”(如果它看起来像鸭子,游起来像鸭子,叫声也像鸭子,那么它很可能就是一只鸭子)。在编程语境中,这句话被引申为:只要一个对象具备特定的方法或属性,就可以按照这些方法或属性所暗示的行为来使用该对象,而无需关注对象的具体类型或继承关系。

核心思想
Duck Typing的核心思想在于关注对象的行为而非其静态类型。在强类型语言中,通常需要显式地指定对象的类型,并且要求对象严格符合该类型定义。而在Python这样的动态类型语言中,duck typing鼓励程序员根据对象实际提供的接口(即其所能响应的方法和拥有的属性)来判断对象是否适用于特定场景,而非基于对象所属的预定义类型。

特点与优势

  1. 动态性:Python在运行时检查对象的方法和属性,而非在编译阶段。这意味着即使两个对象类型不同,只要它们具有相同的方法签名和预期行为,就能在相同上下文中互换使用。

  2. 灵活性:Duck Typing降低了代码对特定类型或类层次结构的依赖,使得代码更加灵活,易于扩展和修改。新加入的类只要满足所需接口,就可以无缝融入现有系统,无需修改原有代码。

  3. 简洁性:由于不需要显式类型检查或复杂的类型转换,使用duck typing的代码通常更为简洁。Python中常见的hasattr()getattr()等函数以及try-except块可用于检测对象是否支持所需的操作,进一步简化代码。

  4. 解耦:Duck Typing促进了模块之间的松耦合。客户端代码无需了解对象的具体类型,只需依赖于对象提供的公共接口,这有助于提高代码的可复用性和可维护性。

实例:

class Duck:def quack(self):print("Quack!")class Parrot:def quack(self):print("Polly wanna cracker!")def make_it_quack(animal):animal.quack()duck = Duck()
parrot = Parrot()make_it_quack(duck)  # 输出: Quack!
make_it_quack(parrot)  # 输出: Polly wanna cracker!

在这个例子中,DuckParrot类虽然类型不同,但都提供了名为quack的方法。make_it_quack函数并不关心传入的animal对象具体是什么类型,只关注它是否有quack方法。因此,不论是Duck对象还是Parrot对象,只要能“quack like a duck”,就可以被函数接受并正确处理。

注意事项
尽管duck typing带来了诸多便利,但也需要注意潜在的问题:

  1. 类型错误:由于运行时才检查类型,可能导致在开发阶段难以发现的类型错误。对此,良好的单元测试和代码审查可以降低风险。

  2. 文档与沟通:由于类型信息不明显,对于大型项目或团队协作,需要清晰的文档和沟通来确保所有参与者理解接口约定。

  3. 性能影响:动态类型检查可能带来轻微的性能开销,但在大多数情况下,这种影响微乎其微,且通常不会成为性能瓶颈。

综上所述,Python中的duck typing是一种基于对象行为而非类型的身份识别原则,它增强了代码的灵活性、简洁性和模块间的解耦,是Python动态类型特性的重要体现。在实践中,合理利用duck typing可以提升代码的可读性、可维护性和可扩展性,但也要注意防范潜在问题,确保代码的健壮性。

3. 多态类的应用场景

  1. 设计模式的实现:许多设计模式如策略模式、工厂模式、装饰器模式等,都离不开多态的支持。通过多态,可以在运行时动态选择合适的对象进行操作,使得设计模式更具灵活性和适应性。

  2. API设计:在设计公共API时,多态有助于构建易于使用的接口。用户只需关注接口名称和参数,无需关心具体实现类的细节,降低了API的学习成本和使用难度。

  3. 测试驱动开发(TDD):多态使得编写针对接口而非实现的测试成为可能,有利于实现隔离测试,提高测试覆盖率和代码质量。

4. 结论

Python中的多态类是实现灵活、可扩展、可维护代码的重要工具。通过接口继承与方法重写、使用抽象基类以及利用duck typing,开发者可以轻松实现多态,并将其应用于设计模式、API设计、测试驱动开发等多种场景中。理解和熟练运用Python多态类,对于提升编程效率和代码质量具有重要意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/10697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day25 代码随想录打卡|栈与队列篇---用队列实现栈

题目(leecode T225): 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 实现 MyStack 类: void push(int x) 将…

嵌入式学习day17

FIFO FIFO也称命名管道,它是一种文件类型 特点 FIFO可以在无关的进程之间交换数据,与无名管道不同FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。FIFO的通信方式类似于在进程中使用文件来传输数据,只不过…

Linux之·网络编程·I/O复用·select

系列文章目录 文章目录 前言一、概述1.1 介绍IO复用的概念和作用1.1.1 I/O复用具体使用的场景1.1.2 I/O复用常用函数 二、select函数的重要性和用途2.1 基本的select函数2.2 如何使用FD_SET、FD_CLR等宏来设置和清除文件描述符集合2.3 select()函数函数整体使用框架&#xff1a…

linux性能监控之slabtop

slabtop命令是以实时的方式显示内核slab缓冲区的细节信息&#xff0c;是linux自带的命令 [rootk8s-master ~]# slabtop --helpUsage:slabtop [options]Options:-d, --delay <secs> delay updates-o, --once only display once, then exit-s, --sort <char&…

服务器硬件命令查看

服务器硬件命令查看 1. 主板 sudo dmidecode -t baseboard2. CPU # CPU型号&#xff08;product→ version&#xff09;、CPU名称&#xff08;id 约定一个名称 cpu cpu:0、cpu:1&#xff09;、厂商(vendor)、主频(size HZ)、核数、架构&#xff08;缺失 product&#xf…

MVC 过滤器

MVC 过滤器常用有4种 Action过滤器&#xff08;IActionFilter&#xff09; 》 行为过滤器Result过滤器 &#xff08;IResultFilter&#xff09;》 视图过滤器 或 结果过滤器Exception过滤器&#xff08;IExceptionFilter&#xff09;》 异常过滤器Authorization过滤器&#xf…

python零基础知识 - 定义列表的三种方式,循环列表索引值

这一小节&#xff0c;我们将从零基础的角度看一下&#xff0c;python都有哪些定义列表的方式&#xff0c;并且循环这个列表的时候&#xff0c;怎么循环&#xff0c;怎么循环他的索引值&#xff0c;怎么拿到的就是元素值。 说完循环&#xff0c;我们会说一说关键的break和contin…

i春秋-GetFlag

题目 考点 sql注入&#xff0c;md5加密&#xff0c;代码审计&#xff0c;利用eval函数 解题 参考wp https://www.cnblogs.com/qiaowukong/p/13630130.html找md5值 看见验证码中的提示&#xff0c;就是去找一个md5值前六位是指定值的数&#xff08;严格来说不一定是数&…

【userfaultfd+条件竞争劫持modprobe_path】TSGCTF 2021 -- lkgit

前言 入门题&#xff0c;单纯就是完成每日一道 kernel pwn 的 kpi &#x1f600; 题目分析 内核版本&#xff1a;v5.10.25&#xff0c;可以使用 userfaultfd&#xff0c;不存在 cg 隔离开启了 smap/smep/kaslr/kpti 保护开启了 SLAB_HADNERN/RANDOM 保护 题目给了源码&…

第二步->手撕spring源码之bean操作

本步骤目标 本步骤继续完善 Spring Bean 容器框架的功能开发&#xff0c;在这个开发过程中会用到较多的接口、类、抽象类&#xff0c;它们之间会有类的实现、类的继承。 这一次我们把 Bean 的创建交给容器&#xff0c;而不是我们在调用时候传递一个实例化好的 Bean 对象&#x…

数据库分库分表思路

一、分库分表的概念 数据过于庞大操作时获取数据缓慢针对于此状况&#xff0c;把原本存储于一个数据库&#xff08;表&#xff09;的数据 按照一定规律分别存储到多个库&#xff08;表&#xff09;。二、为什么要分库分表 当一个程序或系统的不断完善和运行时所负载的业务随着时…

【git】通过JetBrains IDE对git的操作

应该适用于所有jetbrains产品。 一、拉取(pull)代码 上方工具栏-Git-克隆。然后填写git地址与本地存放地址。 二、搁置 修改代码后搁置代码&#xff08;不提交&#xff0c;但是也不撤销已修改的代码&#xff0c;把它暂存起来&#xff09;。 界面的左上角。1->2->3。…

【网站项目】SpringBoot803房屋租赁管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Rust :源代码的分层模块结构组织

在设计和组织多个业务模块的代码时&#xff0c;你需要考虑业务模块之间的耦合度、代码的可维护性以及未来的扩展性。根据你的项目需求&#xff0c;以下是两种常见的组织方式&#xff1a; 1. 每个业务模块都有自己的接口、控制和模型文件夹 如果各个业务模块之间的耦合度较低&…

14.跳跃游戏Ⅱ

文章目录 题目简介题目解答解法一&#xff1a;贪心算法动态规划代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 跳跃游戏Ⅱ 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一&#xff1a;贪心算法动态规划…

《QT实用小工具·六十三》QT实现微动背景,界面看似静态实则动态

1、概述 源码放在文章末尾 该项目实现了微动背景&#xff0c;界面看似静态实则动态&#xff0c;风动&#xff0c;幡动&#xff0c;仁者心动&#xff0c;所以到底是什么在动&#xff1f;哈哈~ 界面会偷偷一点一点改动文字颜色的颜色填充。 虽然是动态&#xff0c;但是慢到难以…

Python---Numpy万字总结(2)

NumPy的应用&#xff08;2&#xff09; 数组对象的方法 获取描述统计信息 描述统计信息主要包括数据的集中趋势、离散程度和频数分析等&#xff0c;其中集中趋势主要看均值和中位数&#xff0c;离散程度可以看极值、方差、标准差等 array1 np.random.randint(1, 100, 10) …

【linux软件基础知识】如何使用 run_list 字段将任务放入就绪队列中

在给定的代码片段中,struct task_struct 表示内核中任务或进程的进程控制块 (PCB)。 run_list 字段的类型为 struct list_head,这表明它是链表实现的一部分。 run_list字段在Linux内核中常用来表示任务在调度队列中的位置,例如就绪队列或各种优先级队列。 init_task是一个…

ubuntu 22.04下面安装cuda、cudnn等的配置过程

一、正常安装ubuntu 22.04系统&#xff0c;安装以后sudo apt update,sudo apt upgrade更新软件到最新版。 二、安装cuda 到下面的地址去下载cuda离线安装包&#xff0c;根据cpu指令集架构等选择正确的选项&#xff1a; https://developer.nvidia.com/cuda-downloads?…

单链表经典算法LeetCode--203.移除链表元素(两种方法解)

1.链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;【点击即可跳转】 分析此题提供两种思路&#xff1a; 1.遍历原链表&#xff0c;将值为val的节点释放掉&#xff08;双指针法&#xff09; 定义一个pcur指针指向头节点&#xff0c;定义一个prev指针指向NULL 需要注…