全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装
全网最适合入门的面向对象编程教程:06 类和对象的 Python 实现-自定义类的数据封装
摘要:
本文我们主要介绍了数据封装的基本概念和特性,如何设置自定义类的私有属性和私有方法,protect 属性的概念和特点。
往期推荐:
全网最适合入门的面向对象编程教程:00 面向对象设计方法导论
全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念
全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类
全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性
全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法
全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签
更多精彩内容可看:
给你的 Python 加加速:一文速通 Python 并行计算
一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库
文档和代码获取
可访问如下链接进行对文档下载:
本文档主要介绍如何使用 Python 进行面向对象编程,需要读者对 Python 语法和单片机开发具有基本了解。相比其他讲解 Python 面向对象编程的博客或书籍而言,本文档更加详细、侧重于嵌入式上位机应用,以上位机和下位机的常见串口数据收发、数据处理、动态图绘制等为应用实例,同时使用 Sourcetrail 代码软件对代码进行可视化阅读便于读者理解。
相关示例代码获取链接如下:
FreakStudio-Python面向对象示例代码
正文
面向对象编程的一个重要特点就是数据封装。在上面的 SerialClass 类中,有关于串口波特率、设备名称等多个属性,我们编写代码的过程中,往往不希望别的模块可以直接访问本模块的数据,而仅通过调用我们的接口函数来访问数据,也就是高内聚和低耦合原则。
在 Python 中,我们可以通过给属性或方法命名时可以用两个下划线作为开头来改变属性和方法的访问权限。在 Python 中,属性和方法的访问权限只有两种,也就是公开的和私有的,对于私有属性或私有方法来说,是不允许外界访问的。
- (1)类的私有属性格式:__private_attrs 两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时__private_attrs。
- (2)类的私有方法格式:__private_method:两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用 self.__private_methods。
这里,我们联系上一节中串口收发的相关方法,可以看到在使用串口收发的相关方法时,我们并没有判断当前串口的状态,如果串口状态为关闭,那么就不能正常工作。于是我们添加了一个__devstate 私有属性用于标识串口状态,同时添加了 RetSerialState()方法用于外界获取串口状态,示例代码如下:
import serial
import serial.tools.list_ports
class SerialClass:
_# 初始化_
_# 使用默认参数_
def __init__(self,
devport = "COM17",
devbaudrate = 115200,
devbytesize = serial.EIGHTBITS,
devparity = serial.PARITY_NONE,
devstopbits = serial.STOPBITS_ONE):
_# 直接传入serial.Serial()类_
self.dev = serial.Serial()
self.dev.port = devport
self.dev.baudrate = devbaudrate
self.dev.bytesize = devbytesize
self.dev.parity = devparity
self.dev.stopbits = devstopbits
_# 表示串口设备的状态-打开或者关闭_
_# 初始化时为关闭_
self.__devstate = False
_# 打开串口_
def OpenSerial(self):
self.dev.open()
self.__devstate = True
_# 关闭串口_
def CloseSerial(self):
self.dev.close()
self.__devstate = False
_# 串口读取_
def ReadSerial(self):
if self.__devstate:
_# 非阻塞方式读取_
_# 按行读取_
data = self.dev.readline()
_# 收到为二进制数据_
_# 用utf-8编码将二进制数据解码为unicode字符串_
_# 字符串转为int类型_
data = int(data.decode('utf-8', 'replace'))
return data
_# 串口写入_
def WriteSerial(self,write_data):
if self.__devstate:
_# 非阻塞方式写入_
self.dev.write(write_data.encode())
_# 输出换行符_
_# write的输入参数必须是bytes 格式_
_# 字符串数据需要encode()函数将其编码为二进制数据,然后才可以顺利发送_
_# \r\n表示换行回车_
self.dev.write('\r\n'.encode())
def RetSerialState(self):
if self.dev.isOpen():
self.__devstate = True
return True
else:
self.__devstate = False
return False
_# 生成串口类的实例_
serdev = SerialClass()
print("serdev state :",serdev.RetSerialState())
serdev.OpenSerial()
print("serdev state :",serdev.RetSerialState())
serdev.CloseSerial()
print("serdev state :",serdev.RetSerialState())
print(serdev.__devstate)
这里我们在初始化方法中使用了默认参数,即在定义方法时,直接给形式参数指定一个默认值,这样的话,即便初始化时没有给拥有默认值的形参传递参数,该参数可以直接使用定义函数时设置的默认值。
代码运行结果如下,可以看到在打开或关闭串口设备时,RetSerialState()方法可以正常获取串口状态,而当我们访问类内私有属性时,程序报错:
好的,现在我们终于松了一口气,声明__devstate 为私有属性后,外部终于无法访问我们的数据了。但是真的是这样吗?
尝试将:
print(serdev.__devstate)
修改为:
print(serdev._SerialClass__devstate)
此时,我们运行程序,发现代码输出如下:
坏了,怎么外界还能访问我们类内私有属性?这是什么魔法?
这是 Python 的名字改装在起作用。Python 不允许实例化的类访问私有数据,但你可以使用 object._className__attrName( 对象名._类名__私有属性名 )访问属性。
由此可知,在 Python 中私有属性为假私有属性。那为什么不从语法上保证 private 字段的私密性呢?用最简单的一句话来说:We are all consenting adults here(我们都是成年人)。正如 Python 程序员的观点:开放要比封闭好。
通过以上讲解,我们实际上已经对类的封装特性有所了解,所谓封装就是:
"隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口"。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。
对于类的私有属性来说,子类是无法访问的,私有变量只有本类的内部能直接调用。这时我们可以用 protect 属性进行修改,在属性和方法前加一个下划线就是 protect 类型了。类的 protect 属性,子类可以继承,同时实例对象、类对象都能直接调用 protect 属性、方法。
受保护属性在类的外部是可见但不建议直接访问,其命名约定表示它们是内部实现的一部分,不应该被直接访问。总体而言,Python 强调封装性,鼓励使用公共方法来访问和修改属性,而不是直接在外部访问。这种做法有助于提高代码的可维护性,防止意外的修改和增加代码的灵活性。
全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装的更多相关文章
- [Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...
- 最适合入门的Laravel中级教程(一)
Laravel 是一个全栈框架: 我们使用 Laravel 开发业务常见有 3 个方向: 前端页面和后端逻辑混合的应用 主要是面向对 SEO 有需求的项目: 比如说新闻资讯博客文章等: 一般在控制器中 ...
- Python入门之面向对象编程(四)Python描述器详解
本文分为如下部分 引言——用@property批量使用的例子来引出描述器的功能 描述器的基本理论及简单实例 描述器的调用机制 描述器的细节 实例方法.静态方法和类方法的描述器原理 property装饰 ...
- Python面向对象02/类的空间问题、类与对象之间的关系、类与类之间的关系
Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 2. 类与对象之间 ...
- python 面向对象专题(二):类的空间问题、类与对象之间的关系、类与类之间的关系
https://www.cnblogs.com/liubing8/p/11308127.html 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 ...
- Python入门之面向对象编程(一)面向对象概念及优点
概念 谈到面向对象,很多程序员会抛出三个词:封装.继承和多态:或者说抽象.一切都是对象之类的话,然而这会让初学者更加疑惑.下面我想通过一个小例子来说明一下 面向对象一般是和面向过程做对比的,下面是一个 ...
- JavaScript基础入门12 - 面向对象编程
目录 JavaScript 面向对象编程 前言 构造函数创建对象 instanceof constructor 返回值 原型对象 关于对象的属性查找 in hasOwnProperty() JS当中实 ...
- [Java入门笔记] 面向对象编程基础(一):类和对象
什么是面向对象编程? 我们先来看看几个概念: 面向过程程序设计 面向过程,是根据事情发展的步骤,按进行的顺序过程划分,面向过程其实是最为实际的一种思考方式,可以说面向过程是一种基础的方法,它考虑的是实 ...
- JavaScript中的面向对象编程,详解原型对象及prototype,constructor,proto,内含面向对象编程详细案例(烟花案例)
面向对象编程: 面向:以什么为主,基于什么模式 对象:由键值对组成,可以用来描述事物,存储数据的一种数据格式 编程:使用代码解决需求 面向过程编程: 按照我们分析好的步骤,按步 ...
- 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法
1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...
随机推荐
- 你知道 Java 有哪些引用吗?
前言 判断对象是否要回收有引用计数法和可达性算法两种方式,无论哪种都离不开引用,本文将介绍Java的四种引用. 一.概述 二.详解 1. 强引用 概述 在Java程序中,强引用是最常见的也是默认的.n ...
- java学习之旅(day.05)
switch多选择结构 多选择结构还有一个实现方式就是switch case switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支 switch(expression ...
- 智能便捷_AIRIOT智慧充电桩管理解决方案
现如今随着对可持续交通的需求不断增加,电动车市场正在迅速扩大,建设更多更智能的充电桩,并通过管理平台提高充电设施的可用性和效率成为一项重要任务.传统的充电桩管理平台在对充电设施进行管理过程中,存在如下 ...
- vulnhub靶场 --> Red: 1
靶机下载地址 Red: 1 << 点我 开始打靶 IP发现 nmap扫描网段发现靶机ip:192.168.111.142 端口发现 对靶机进行常规端口扫描 访问网站 到处点击发现存在一个可 ...
- 一些常用但是不好记的css样式
设置滚动条样式 /*定义滚动条宽高及背景,宽高分别对应横竖滚动条的尺寸*/ ::-webkit-scrollbar { width: 10px; /*对垂直流动条有效*/ height: 10px; ...
- PyQGIS二次开发指南
当你的数据处理使用的是Python语言,而你的导师又让你开发界面,那么PyQGIS二次开发指南是你必读的圣经.QGIS支持Python语言进行二次开发,你将学会如何使用Qt Designer进行界面设 ...
- Native如何使用Tunnel Mode
mAudioSessionId = AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION); mHwSync = AudioSystem: ...
- 基于WebSocket的modbus通信(一)- 服务器
ModbusTcp协议是基于tcp的,但不是说一定要通过tcp协议才能传输,只要能传输二进制的地方都可以.比如WebSocket协议. 但由于目前我只有tcp上面的modbus服务器实现,所以我必须先 ...
- redhat8 添加scsi类型的硬盘后开机重配虚拟机 且黑屏
原因:因为vmware磁盘优先级里nvme类型的磁盘比scsi类型的磁盘优先级高,所以开机先启动scsi类型的磁盘 又因为scsi并不是系统盘所以不能够实现开机 解决方法: 改变vmware的磁盘优先 ...
- IDEA顺序启动多个Spring Boot微服务
上个月公司新开发的一个项目,需要使用微服务,将单体服务拆分成多个微服务.但是每次修改代码之后都需要启动多个微服务,改个代码,都要修改五分钟,启动半小时,但是idea可以设置将多个服务依次启动,减少操作 ...