全网最适合入门的面向对象编程教程:06 类和对象的 Python 实现-自定义类的数据封装

摘要:

本文我们主要介绍了数据封装的基本概念和特性,如何设置自定义类的私有属性和私有方法,protect 属性的概念和特点。

往期推荐:

学嵌入式的你,还不会面向对象??!

全网最适合入门的面向对象编程教程:00 面向对象设计方法导论

全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念

全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类

全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性

全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法

全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签

更多精彩内容可看:

给你的 Python 加加速:一文速通 Python 并行计算

一文搞懂 CM3 单片机调试原理

肝了半个月,嵌入式技术栈大汇总出炉

电子计算机类比赛的“武林秘籍”

一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库

文档和代码获取

可访问如下链接进行对文档下载:

FreakStudio-Python面向对象文档

本文档主要介绍如何使用 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实现-自定义类的数据封装的更多相关文章

  1. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  2. 最适合入门的Laravel中级教程(一)

    Laravel 是一个全栈框架: 我们使用 Laravel 开发业务常见有 3 个方向: 前端页面和后端逻辑混合的应用 主要是面向对 SEO 有需求的项目: 比如说新闻资讯博客文章等: 一般在控制器中 ...

  3. Python入门之面向对象编程(四)Python描述器详解

    本文分为如下部分 引言——用@property批量使用的例子来引出描述器的功能 描述器的基本理论及简单实例 描述器的调用机制 描述器的细节 实例方法.静态方法和类方法的描述器原理 property装饰 ...

  4. Python面向对象02/类的空间问题、类与对象之间的关系、类与类之间的关系

    Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 2. 类与对象之间 ...

  5. python 面向对象专题(二):类的空间问题、类与对象之间的关系、类与类之间的关系

    https://www.cnblogs.com/liubing8/p/11308127.html 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 ...

  6. Python入门之面向对象编程(一)面向对象概念及优点

    概念 谈到面向对象,很多程序员会抛出三个词:封装.继承和多态:或者说抽象.一切都是对象之类的话,然而这会让初学者更加疑惑.下面我想通过一个小例子来说明一下 面向对象一般是和面向过程做对比的,下面是一个 ...

  7. JavaScript基础入门12 - 面向对象编程

    目录 JavaScript 面向对象编程 前言 构造函数创建对象 instanceof constructor 返回值 原型对象 关于对象的属性查找 in hasOwnProperty() JS当中实 ...

  8. [Java入门笔记] 面向对象编程基础(一):类和对象

    什么是面向对象编程? 我们先来看看几个概念: 面向过程程序设计 面向过程,是根据事情发展的步骤,按进行的顺序过程划分,面向过程其实是最为实际的一种思考方式,可以说面向过程是一种基础的方法,它考虑的是实 ...

  9. JavaScript中的面向对象编程,详解原型对象及prototype,constructor,proto,内含面向对象编程详细案例(烟花案例)

    面向对象编程:   面向:以什么为主,基于什么模式 对象:由键值对组成,可以用来描述事物,存储数据的一种数据格式 编程:使用代码解决需求   面向过程编程:         按照我们分析好的步骤,按步 ...

  10. 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法

    1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...

随机推荐

  1. 使用 JS 实现在浏览器控制台打印图片 console.image()

    在前端开发过程中,调试的时候,我门会使用 console.log 等方式查看数据.但对于图片来说,仅靠展示的数据与结构,是无法想象出图片最终呈现的样子的. 虽然我们可以把图片数据通过 img 标签展示 ...

  2. jupyter notebook无法找到自己的虚拟环境

    1:打开cmd/Anaconda Prompt/Anaconda Powershell Prompt 2:进入虚拟环境conda activate 环境名 3:conda list查看有无ipyker ...

  3. Ceph 架构以及部署

    目录 Ceph架构 存储类型 为什么用到Ceph? 1. NFS 2. MooseFS MooseFS瓶颈 3. GlusterFS 4. Ceph Ceph的组件 Ceph部署 前期准备 1.1 修 ...

  4. ajax跨域(跨源)方案之CORS

    ajax跨域(跨源)方案:后端授权[CORS],jsonp,服务端代理 CORS是一个W3C标准,全称是"跨域资源共享",它允许浏览器向跨源的后端服务器发出ajax请求,从而克服了 ...

  5. .NetCore 3.1 教程之 EFCore连接Mysql DBFirst模式 从数据库生成实体

    一:创建EF的类库,同时将此项目设置为启动项(为Scaffold-DbContext -tables指令使用),同时安装2个包   ①Microsoft.EntityFrameworkCore.Too ...

  6. 领域驱动设计(Domain-Driven Design,简称DDD)【简介 个人学习笔记】

    找到了第 1 篇资料:领域驱动设计详解:是什么.为什么.怎么做? - 知乎 找到了第 2 篇资料:领域驱动架构(DDD)建模中的模型到底是什么? - 知乎 找到了第 3 篇资料:一文看懂DDD 领域驱 ...

  7. python-一种字符串排序方式

    最近工作中,需要使用python实现一种排序方式,简要说明如下: 1.排序方式 假设有一个序列,数据为:['n1', 'n2', 'n10', 'n11', 'n21', 'n3', 'n13', ' ...

  8. Java常用的三个方法 `wait ` `notify` `notifyAll`

    常用的三个方法 wait notify notifyAll wait();方法使当前线程进入等待状态,直到另一个线程调用该对象的notify()或notifyAll()方法来唤醒它 notify(); ...

  9. React脚手架 创建React项目

    React团队主要推荐使用create-react-app来创建React新的单页应用项目的最佳方式. React脚手架(create-react-app)意义 脚手架是官方提供,零配置,无需手动配置 ...

  10. EF MYSQL DB FIRST 出现2次数据库名

    环境:使用ADO设计器添加的数据库实体,运行时出现 :Table 'world.world.city' doesn't exist . world 是mysql的演示数据库. MySql.Data.E ...