全网最适合入门的面向对象编程教程:10 类和对象的 Python 实现-类的继承和里氏替换原则,Python 模拟主机和传感器自定义类
全网最适合入门的面向对象编程教程:10 类和对象的 Python 实现-类的继承和里氏替换原则,Python 模拟主机和传感器自定义类
摘要:
本文主要介绍了类的继承的基本概念和里氏替换原则,以模拟传感器数据串口输出-上位机串口接收为例,对工作流程、工作模式和基本概念进行讲解,同时创建了主机类和传感器类,定义了属性和抽象方法。
原文链接:
往期推荐:
全网最适合入门的面向对象编程教程:00 面向对象设计方法导论
全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念
全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类
全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性
全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法
全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签
全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装
全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解
全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器
全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系
更多精彩内容可看:
给你的 Python 加加速:一文速通 Python 并行计算
一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库
文档和代码获取
可访问如下链接进行对文档下载:
https://github.com/leezisheng/Doc
本文档主要介绍如何使用 Python 进行面向对象编程,需要读者对 Python 语法和单片机开发具有基本了解。相比其他讲解 Python 面向对象编程的博客或书籍而言,本文档更加详细、侧重于嵌入式上位机应用,以上位机和下位机的常见串口数据收发、数据处理、动态图绘制等为应用实例,同时使用 Sourcetrail 代码软件对代码进行可视化阅读便于读者理解。
相关示例代码获取链接如下:https://github.com/leezisheng/Python-OOP-Demo
正文
类的继承的基本概念
刚才我们提到了,可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。
里氏替换原则
所谓里氏替换原则通俗来说就是子类可以扩展父类的功能,但不能改变父类原有的功能。有以下几个引申含义:
- (1)子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- (2)子类中可以增加自己特有的方法。
- (3)当子类的方法重载父类的方法时,方法的前置条件(方法的输入,入参)要比父类的入参更宽松。
- (4)当子类的方法实现父类的方法时(重写,重载,实现抽象方法),方法的后置条件(输出、返回值)要比父类更严格或相等。
更多相关信息可以看:https://www.jyt0532.com/2020/03/22/lsp/
应用实例的抽象实现
这里,我们以模拟传感器数据串口输出-上位机串口接收为例,进行讲解:在现在的开发中,许多传感器都内部集成了 ADC 和 MCU 芯片,可以将采集到的传感器测量的物理量对应的电压量进行转换并进行滤波等处理后,将更精确的传感器数据通过串口进行输出。这里,传感器和上位机间关于串口通信的部分就可以抽象为串口类,二者都具有串口的收发功能。但传感器类和上位机接收类与串口类有有所不同:
SensorClass 类 | |
---|---|
类内成员 | 作用 |
属性 attribute:sensorvalue | 传感器采集的数据 |
属性 attribute:sensorid | 传感器 ID 号,用于识别是哪个传感器 |
** **** **属性 attribute:sensorstate | 传感器工作状态,包括:** ① 被动响应模式(默认):主机发送查询数据指令后,传感器发送数据;**** ② 轮询工作模式:间隔 100ms 发送一个传感器数据,轮询工作;** |
方法 operation:SendSensorID | 发送传感器 ID 号 |
方法 operation:SendSensorValue | 发送传感器采集的数据 |
方法 operation:RecvMasterCMD | 接收主机指令 |
方法 operation:StartSensor | 开始传感器工作 |
方法 operation:StopSensor | 停止传感器工作 |
方法 operation:InitSensor | 初始化传感器 |
工作流程简单来说就是传感器初始化后开始工作,不断采集数据,接收到主机发送的查询数据命令后,发送传感器数据;对应的接收到主机发送的不同指令后执行对应操作。
我们来看如下示例代码,SensorClass 类具体方法实现先省略:
class SensorClass(SerialClass):
_# 类的初始化_
def __init__(self,id,state):
_# 调用父类的初始化方法,super() 函数将父类和子类连接_
super().__init__()
self.sensorvalue = 0
self.sensorid = id
self.sensorstate = state
_# 传感器上电初始化_
def InitSensor(self):
pass
_# 开启传感器_
def StartSensor(self):
pass
_# 停止传感器_
def StopSensor(self):
pass
_# 发送传感器ID号_
def SendSensorID(self):
pass
_# 发送传感器数据_
def SendSensorValue(self):
pass
这里,继承语法为:
class 派生类名(基类名)
...
在 SensorClass 类的初始化方法中,我们首先调用如下语句:
super().__init__()
这里,super()用来调用父类(基类)的方法,init()是类的构造方法, super().init() 就是调用父类的 init 方法, 同样可以使用 super()去调用父类的其他方法。这里,你可能会问,我们为何不用如下语句来初始化父类 SerialClass 呢?
SerialClass.__init__()
这看起来多清晰、多方便。实际上,super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。这里,不对钻石继承问题做过多叙述,只需知道子类初始化时必须调用 super() 方法。
有关钻石继承问题可以查看如下链接:
https://blog.csdn.net/qq_41556318/article/details/84521836
对于主机的 MasterClass 类来说,除了继承于父类 SerialClass 的属性和方法外,还包括其他属性和方法,如下讲解:
MasterClass 类 | |
---|---|
类内成员 | 作用 |
属性 attribute:valuequeue | 主机中传感器采集数据的缓存队列 |
属性 attribute:masterstate | 主机状态,包括:① 空闲状态(默认):主机工作空闲,可以接收数据;② 忙碌状态:主机工作忙碌,暂时停止数据接收。 |
方法 operation:RecvSensorID | 接收传感器 ID 号 |
方法 operation:RecvSensorValue | 接收传感器采集的数据 |
方法 operation:SendSensorCMD | 发送主机指令 |
方法 operation:StartMaster | 开始主机工作 |
方法 operation:StopMaster | 停止主机工作 |
方法 operation:RetMasterState | 返回主机状态 |
工作流程简单来说就是主机在空闲时,发送数据查询指令,接收传感器数据;在忙碌时,不接收数据。
我们来看如下示例代码,MasterClass 类具体方法实现先省略:
class MasterClass(SerialClass):
_# 类的初始化_
def __init__(self,state):
_# 调用父类的初始化方法,super() 函数将父类和子类连接_
super().__init__()
self.valuequeue = queue.Queue(5)
self.masterstatue = state
_# 开启主机_
def StartMaster(self):
pass
_# 停止主机_
def StopMaster(self):
pass
_# 接收传感器ID号_
def RecvSensorID(self):
pass
_# 接收传感器数据_
def RecvSensorValue(self):
pass
_# 主机发送命令_
def SendSensorCMD(self):
pass
_# 主机返回工作状态_
def RetMasterStatue(self):
pass
这里,我们使用队列创建了一个传感器数据缓冲区:
self.valuequeue = queue.Queue(5)
我们使用 import queue 语句导入队列库,队列类似于一条管道,元素先进先出,元素进入使用 put()方法,元素获取使用 get( )方法。关于新建的两个类方法的具体实现可以看下一节内容。
全网最适合入门的面向对象编程教程:10 类和对象的 Python 实现-类的继承和里氏替换原则,Python 模拟主机和传感器自定义类的更多相关文章
- [Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...
- 最适合入门的Laravel中级教程(一)
Laravel 是一个全栈框架: 我们使用 Laravel 开发业务常见有 3 个方向: 前端页面和后端逻辑混合的应用 主要是面向对 SEO 有需求的项目: 比如说新闻资讯博客文章等: 一般在控制器中 ...
- [.net 面向对象编程基础] (10) 类的成员(字段、属性、方法)
[.net 面向对象编程基础] (10) 类的成员(字段.属性.方法) 前面定义的Person的类,里面的成员包括:字段.属性.方法.事件等,此外,前面说的嵌套类也是类的成员. a.类的成员为分:静态 ...
- C# 实例解释面向对象编程中的里氏替换原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- 第2章 面向对象的设计原则(SOLID):2_里氏替换原则(LSP)
2. 里氏替换原则(Liskov Substitution Principle,LSP) 2.1 定义 (1)所有使用基类的地方必须能透明地使用子类替换,而程序的行为没有任何变化(不会产生运行结果错误 ...
- 【面向对象设计原则】之里氏替换原则(LSP)
里氏代换原则由2008年图灵奖得主.美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing 教授于1994年提出,所以使用的是这位女博士的性命名的一个 ...
- 面向对象设计原则 里氏替换原则(Liskov Substitution Principle)
里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一. 里氏替换原则中说,任何基类可以出现的地方,子类一定可以出现. LSP是继承复用的基石,只 ...
- Python入门之面向对象编程(一)面向对象概念及优点
概念 谈到面向对象,很多程序员会抛出三个词:封装.继承和多态:或者说抽象.一切都是对象之类的话,然而这会让初学者更加疑惑.下面我想通过一个小例子来说明一下 面向对象一般是和面向过程做对比的,下面是一个 ...
- JavaScript基础入门12 - 面向对象编程
目录 JavaScript 面向对象编程 前言 构造函数创建对象 instanceof constructor 返回值 原型对象 关于对象的属性查找 in hasOwnProperty() JS当中实 ...
- [Java入门笔记] 面向对象编程基础(一):类和对象
什么是面向对象编程? 我们先来看看几个概念: 面向过程程序设计 面向过程,是根据事情发展的步骤,按进行的顺序过程划分,面向过程其实是最为实际的一种思考方式,可以说面向过程是一种基础的方法,它考虑的是实 ...
随机推荐
- Delaunay三角剖分实现
参考文章:https://www.cnblogs.com/zhiyishou/p/4430017.html 本文使用逐点插入法进行剖分,并使用Unity3D实现. 通过阅读文章<Triangul ...
- vulnhub靶场 --> Red: 1
靶机下载地址 Red: 1 << 点我 开始打靶 IP发现 nmap扫描网段发现靶机ip:192.168.111.142 端口发现 对靶机进行常规端口扫描 访问网站 到处点击发现存在一个可 ...
- SuperSocket AppServer.NewRequestReceived 不触发 接受不到字节
SuperSocket AppServer.NewRequestReceived 不触发 接受不到字节 针对.netframework版本 1.6.* 使用 FixedHeaderReceiveFil ...
- Flutter(三):Flutter App 可行性分析
一.生态建设 第三方Package https://pub.dev/packages?sort=popularity 截止2021年4月,第三方库达到17000+ 二.Devops 代码风格检查 An ...
- 鸿蒙HarmonyOS实战-Web组件(Cookie及数据存储)
前言 Cookie是一种存储在用户计算机上的小文本文件,用于在用户访问网站时存储和提取信息.它由网站服务器发送到用户的浏览器,并存储在用户的计算机上.每当用户访问该网站时,浏览器将发送该Cookie回 ...
- 7.12考试总结(NOIP模拟12)[简单的区间·简单的玄学·简单的填数]
即使想放弃,也没法放弃最想要的东西,这就是人 前言 这次应该是和 SDFZ 一起打的第一场比赛吧. 然而我还是 FW 一个... 这次考试也有不少遗憾,主要的问题是码力不足,不敢去直面正解,思考程度不 ...
- 《利用python进行数据分析》笔记章节索引
本文章作为我的一系列关于<利用python进行数据分析>的笔记的文章的索引.分为四部分. 第一部分:numpy基础,共六节: numpy基础--ndarray(一种多维数组对象):http ...
- 安装并使用 openssl 生成证书
1. 安装 openssl参考链接: OpenSSL加密算法库使用系列教程_openssl算法哭调用-CSDN博客 安装包下载地址: 安装包下载地址(正常情况需要将 openssl 源码下载后, 自己 ...
- 时间格式化转换及时间比较compareTo,Controller层接收参数格式化,从数据源头解决时间格式错误数据对接口的影响
时间格式化转换及时间比较compareTo,Controller层接收参数格式化,从数据源头解决时间格式错误数据对接口的影响 /** * 时间格式的转换:在具体报错的地方做转换,可能不能从根本上面解决 ...
- java中判断一个String字符串或字符数组中包含某个字段
/** * 判断String字符串中包含某个字段 * @param oriStr 原始字符串 * @return */ private static boolean findString(String ...