python中的抽象基类
目录
- 协议和鸭子类型
- 抽象基类
- 定义抽象基类
- 使用抽象基类
- 直接继承
- 通过注册(register)
- __subclasshook__魔法方法
协议和鸭子类型
python中有大量的魔法方法,python所谓基于协议编程,就是依赖这些魔法方法。
什么意思呢?
比如我们想要实现一个对象,让他可以有序列的特征(可切片、可遍历等特征),那么我们只要实现__len__
和 __getitem__
两个方法即可。任何类, 要使用标准的签名和语义实现了这两个方法,就能用在任何期待序列的地方。是不是哪个类的子类无关紧要,只要提供了所需的方法即可。
如下例:
class FrenchDeck:def __init__(self, seq):self._cards = list(seq)def __len__(self):return len(self._cards)def __getitem__(self, position):return self._cards[position]if __name__ == "__main__":obj = FrenchDeck([1, 2, 3, 4, 5])# 可切片print(obj[2])# 可遍历for i in obj:print(i)
FrenchDeck对象没有任何人告诉过它是一个序列,但是由于python基于协议来表现,它的表现却很像一个序列,那么就可以说FrenchDeck对象时一个序列。这就是鸭子类型。
可以通俗理解为:不管这个类是不是一个鸭子,只要它的表现像鸭子(有羽毛、会游泳,嘎嘎叫),那么久可以称之为鸭子。
抽象基类
前面也了解到python是基于协议的,引入抽象基类之前,Python 就已经非常成功了,即便现在也很少有代码使用抽象基类。
一般也不建议我们自己去定义抽象基类,抽象基类一般只会在框架中看到,这里只是为了学习知识。
抽象类有什么作用:抽象基类是一种特殊的类,它只用于作为其他类的基础(父类)。它定义了一些必须要实现的方法,而这些方法在子类中必须被重写,以便于子类能够正常工作。它提供了一种方式来定义和强制执行类必须实现的方法,一般自己不能被实例化。
定义抽象基类
其实python中并没有像java中有interface
关键字可以来定义抽象基类。python中定义抽象基类一般是通过abc模块创建,它提供了ABC
(Abstract Base Class)类来实现这个功能。要定义一个抽象基类,请从ABC类派生一个类,并使用@abstractmethod
装饰器将方法标记为抽象方法。
示例如下:
from abc import ABC, abstractmethodclass MyAbstractClass(ABC):@abstractmethoddef my_abstract_method(self):pass
在上面的代码中,MyAbstractClass
继承自ABC
类,并且使用了@abstractmethod
装饰器来声明一个抽象方法my_abstract_method()
。注意到在该函数内部并没有实现任何具体的逻辑,而是使用了pass
语句进行占位符处理。这表明该方法必须在子类中被重写。
当我们定义完抽象基类之后,我们可以将其作为其他类的基类,使得子类必须实现抽象基类中定义的抽象方法,并且在运行时检查子类是否实现了这些方法。如果子类没有实现完整的抽象方法,那么在实例化时就会引发TypeError异常。
需要注意的是抽象类可能同时包含具体方法和抽象方法。
使用抽象基类
具体化抽象类可以有两种方式,一种通过注册(register),另外一种通过继承。
直接继承
当一个类继承了抽象基类,那么子类就必须实现抽象基类里的抽象方法,否则报错。
from abc import ABC, abstractmethodclass Shape(ABC):@abstractmethoddef area(self):pass@abstractmethoddef perimeter(self):passclass Square(Shape):def __init__(self, side):self.side = sidedef area(self):return self.side ** 2def perimeter(self):return self.side * 4s = Square(5)
print(s.area()) # 输出 25
print(s.perimeter()) # 输出 20
在上面的代码中,定义了一个抽象基类Shape
,并在其中定义了两个抽象方法area
和perimeter
。然后,我们定义了一个Square
类,继承自Shape
类并实现了其中的两个抽象方法。
当我们创建Square
类的对象时,它将拥有Shape
类中定义的接口和行为。通过这种方式,我们可以强制要求子类定义特定的方法,并在需要时使用它们。
通过注册(register)
Python的abc模块提供了一个register
方法,可以用于将类注册为抽象基类的虚拟子类,即使它没有明确继承该类也可以被视为其子类。
下面是一个示例代码:
from abc import ABC, abstractmethodclass Shape(ABC):@abstractmethoddef area(self):pass@abstractmethoddef perimeter(self):passclass Square:def __init__(self, side):self.side = sidedef area(self):return self.side ** 2def perimeter(self):return self.side * 4Shape.register(Square)s = Square(5)
print(isinstance(s, Shape)) # 输出 True
print(s.area()) # 输出 25
print(s.perimeter()) # 输出 20
在这个示例中,我们定义了一个Shape
类作为抽象基类,并定义了两个抽象方法area
和perimeter
。然后,我们定义了一个Square
类,它没有明确继承自Shape
类,但我们通过调用Shape.register
方法将其注册为Shape
类的虚拟子类。因此,即使Square
类没有显式地继承Shape
类,我们仍然可以将其视为Shape
类的实例,并在其中调用Shape
类中定义的方法。
在python3.3后,也可以通过装饰器的方式:
@Shape.register
class Square:...
通过使用register
方法,我们可以更灵活地定义抽象基类和子类之间的关系,并确保所有必需的方法都得到了正确实现。
__subclasshook__魔法方法
在 Python 中,__subclasshook__
方法是一个特殊方法,它可以用来控制子类的继承关系。当一个类被调用了 issubclass()
函数时,Python 会自动搜索其基类中是否定义了 subclasshook
方法。如果找到了,就会用该方法返回的布尔值来判断该类是否为子类。
几点说明:
- 该方法定义在抽象基类中
- 该方法必须定义为类方法
- 该方法有三个返回值
True: 如果测试类被认为是子类
False: 如果测试类不被认为是子类
NotImplemented: 子类未实现执行方法
先看下python里自己实现的一个类Sized
,其源码如下:
class Sized(metaclass=ABCMeta):__slots__ = ()@abstractmethoddef __len__(self):return 0@classmethoddef __subclasshook__(cls, C):if cls is Sized:return _check_methods(C, "__len__")return NotImplemented
如上所示,我们看到了它实现了__subclasshook__
方法,检查子类和子类的mro
上所有的类是否有__len__
方法,如果没有,返回NotImplemented
。当然我们不必继承Sized
,而是使用虚拟子类(virtual subclass)技术,只实现__len__
协议,就可以隐式继承了Sized
。
下面我们仿造Sized自定义一个抽象基类
import abc
class Base(abc.ABC):@abc.abstractmethoddef my_protocol(self):"""自定义协议"""@classmethoddef __subclasshook__(cls, subclass):if cls is Base:if any("my_protocol" in B.__dict__ for B in subclass.__mro__):return Truereturn NotImplemented
接下来我们定义一个子类,隐式继承Base
class MyClass:def my_protocol(self):passif __name__ == '__main__':obj = MyClass()# isinstance查询示例obj是否是Base的实例print(isinstance(obj, Base)) # True# issubclass查询MyClass是否是Base的子类print(issubclass(MyClass, Base)) # True# 查询Base类的虚拟子类print(Base._abc_impl)
如上所示,我们只需要实现my_protocol协议,就会隐式继承自抽象基类,这样就实现了虚拟子类的创建。
参考:
https://www.python51.com/jc/17075.html
相关文章:
python中的抽象基类
目录 协议和鸭子类型抽象基类定义抽象基类使用抽象基类直接继承通过注册(register) __subclasshook__魔法方法 协议和鸭子类型 python中有大量的魔法方法,python所谓基于协议编程,就是依赖这些魔法方法。 什么意思呢?…...

耗时几个月,终于决定把原本想用于商业的系统开源了
前言 嗨,大家好,我是希留,一个被迫致力于全栈开发的老菜鸟。 今天又来给小伙伴们分享一个基于 SpringBoot Vue 实现的前后端分离后台管理系统项目; 简介 这个项目是基于xiliu-tenant脚手架项目搭建而成,原本是帮朋…...

HarmonyOS应用端云一体化开发主要流程
图示 主要步骤 序号 阶段 任务 说明 1 创建端云一体化开发工程 选择工程类型与云开发模板 确定工程类型:选择“Application”或“Atomic Service”页签,确定创建的是HarmonyOS应用工程还是原子化服务工程。选择云开发模板,包括通用云开…...
NoSQL之 Redis配置与优化
NoSQL之 Redis配置与优化 ---------------------- 关系数据库与非关系型数据库 ---------------------------------------- ●关系型数据库: 关系型数据库是一个结构化的数据库,创建在关系模型(二维表格模型)基础上,一…...

Redis哨兵模式
1.哨兵模式是什么 解释一 哨兵巡查监控 master主机是否故障,如果故障了,根据投票数自动将一个从库转换为新数据库,继续对外服务。 解释二 监控redis 的运行状态,包括master和slave当master宕机后,能自动将slave切换…...

数据库管理-第七十六期 如何升级19c RAC(20230516)
数据库管理 2023-05-16 第七十六期 如何升级19c RAC1 回头处理2 升级AHF3 升级GI及DB3.1 拷贝所需文件3.2 升级OPatch3.3 升级GI与DB3.4 应用SQL变更 4 升级OJVM4.1 解压补丁4.2执行补丁冲突检查:4.3 升级OJVM4.4 应用SQL变更 5 最终验证总结 第七十六期 如何升级19…...

组合预测模型 | ARIMA-CNN-LSTM时间序列预测(Python)
组合预测模型 | ARIMA-CNN-LSTM时间序列预测(Python) 目录 组合预测模型 | ARIMA-CNN-LSTM时间序列预测(Python)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 ARIMA-CNN-LSTM是一种结合了传统时间序列模型和深度学习模型的…...

实验四 面向对象分析与设计——UML类图与时序图
一、实验目的: 掌握面向对象分析中静态结构模型与动态行为模型的基本思想。学会识别系统中的类、类的属性和操作以及类之间的关系,掌握UML类图的绘制方法。了解时序图的作用和组成元素,掌握UML时序图的绘制方法。 二、实验仪器及实验环境&a…...

最短路径问题
如图,设定源点为D,终点为A,则D到A的最短路径是多少? 算法思路: 第一步,从源点D出发,此时能到达的选择是C和E,我们根据路径长度选择最少的作为下一个节点,于是选择C&…...

国内有哪些SAAS软件?SAAS软件有哪些优点?
国内有哪些SAAS软件?SAAS软件有哪些优点?不请自来答一下,通过SaaS软件与传统软件的对比来详细讲下SaaS软件有哪些优点? 配合以下内容食用更佳: 关于概念——深度详解什么是SaaS(软件即服务)关…...

分享两组不同的3D VR卡片
最近某音上出现了很多VR视频,转动手机可以看到手机界面未显示出来的场景。这种事情我觉得我们也可以做到。 所以两种不同的3D VR卡片来了: 第一种是横向或上下可以拖动极大的距离。卡片上的信息会随着拖动移动,但不会显示更多的信息&#x…...

外贸人如何精准开发客户?Facebook开发客户全攻略
现在做跨境的都了解的一个社媒平台就是Facebook了,因为很多人都会拿Facebook来开发客户,忙里偷闲,今天东哥就来聊聊用Facebook开发客户的一些心得。 用Facebook开发客户的心得 1、利用关键词搜索 使用行业相关的关键词、产品特定的关键词、相…...

一、Git安装(Git+TortoiseGit图形化)
Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式…...
mysql死锁,如何产生?如何发现?如何处理?
1 产生死锁 就是资源互斥 例子如下 好的,请参考以下 SQL 语句来创建 base_account_item 表和向表中插入一些数据: CREATE TABLE base_account_item (id INT(11) NOT NULL,account_item_name VARCHAR(50) NOT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEF…...

YOLO V1-V3 简单介绍
目录 1. YOLO 2. YOLO V1 3. YOLO V2 4. YOLO V3 5. YOLO V3 SPP网络 5.1 Mosaic 图像增强 5.2 SPP 模块 5.3 CIou Loss 5.4 Focal loss 1. YOLO YOLO 是目标检测任务强大的算法,将目标检测的问题转换边界框和相关概率的回归问题,是目标检测…...

数据结构总结1:了解数据结构、时间复杂度、空间复杂度
后续可能会有补充和更改 目录 一、数据结构 1.算法介绍 二、时间复杂度、空间复杂度 三、练习 1.时间复杂度 2.空间复杂度 一、数据结构 数据结构是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。 数据结构和数据库的区…...
abstract class和interface有什么区别?
含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以…...

Kafka在Java项目中的应用
Kafka在Java项目中的应用 Docker 安装Kafka 一.首先需要安装docker,可看这篇文章安装docker 二.拉取zookeeper和KafKa镜像 docker pull wurstmeister/zookeeperdocker pull wurstmeister/kafkaKafka组件需要向zookeeper进行注册,所以也需要安装zookeeper 三.启动zookeeper…...
理解分布式id生成算法SnowFlake
理解分布式id生成算法SnowFlake 分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种。 概述 SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图: } public function __construct(){ $this->rnew…...

光纤收发器可以连接光模块吗?
随着科技的进步发展,城市信息化速度的加快,光通信产品在数据中心和安防监控等场景中的运用越来越广泛,而这之间的连接则需要光模块和光纤收发器来实现。很多用户对光模块和光纤收发器的使用有些疑虑,两者该如何连接?又…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...