第7.23节 Python使用property函数定义属性简化属性访问的代码实现
第7.23节 Python使用property函数定义属性简化属性访问的代码实现
一、 背景
在本章前面章节中,我们介绍了类相关的知识,并举例进行了说明,在这些例子中会定义一些形如 “get属性”、“set属性”的实例属性的存取方法,当实例数据的属性是私有时,这些数据的访问都只能通过存取方法进行方法,而没有设置为私有的实例数据如果要遵循特定的规则可能也只能通过存取方法访问。但如果一个程序要访问比较多的实例的数据时,大量使用这种存取方法会让程序显得单调而冗长。为了解决该问题,Python提供了一种机制,可以象使用普通类实例变量访问那样访问这些属性,并能确保使用类定义的访问方法来进行相关访问,相当于类似于普通实例变量赋值、查询、删除的访问方法,但真正执行则依靠类定义的属性访问方法。这个就是使用property函数来定义实例属性进行访问。
二、 语法释义
1. 定义语法就是对于要定义的实例属性在类体代码中增加如下一行语句:
实例属性=property(fget=None, fset=None, fdel=None, doc=None)
例如在类Rectangle中定义了长方形的长的访问方法getLen,setLen,且长方形的长存储在一个实例变量length甚至是一个私有变量__length中,我们可以使用如下语句在类内定义一个新的实例属性来访问长方形的长:
len = property(getLen,setLen,None,'长方形的长')
2. 语法释义
1) 实例属性:是指以后要通过这种模式访问的属性名,该属性名必须使用新定义的实例属性,不能用原来已经定义的属性,以后相关数据的访问依靠该属性进行;需要特别说明的是,新定义的这个实例属性可以和一个或多个实例变量关联,具体关联是通过get和set方法去设置的,比如上面的例子,在类内应该有如下两个实例方法:
def setLen(self,length):self.__length=length
def getLen(self): return self.__length
2) 上面的方法定义实例属性的类型并不是哪个实例变量的属性,而是一个类型为”property”新对象,在其中会保存需要访问的真正实例变量对应操作的方法。property并不是一个真正的函数,它是一个拥有许多特殊方法的类,Property对象有三个方法,getter(), setter()和delete(),用来在对象创建后设置fget,fset和fdel方法。其本质是把调用属性访问的方法伪装成对新定义属性的访问。
3) property函数的四个参数:
a) 四个参数按顺序依次为get读取属性方法、set设置属性方法、del 删除属性方法和 doc,其中前三个参数对应三个实例方法分别进行某个或某些属性的读取、设置和删除, doc 是一个文档字符串,用于说明该新定义的属性,在这些方法里可以执行相关校验和数据处理变换,以保证数据访问的正确性;
b) 在实际使用时,调用 property 也可传入 0 个(既不能读,也不能写的属性)、1 个(只读属性)、2 个(读写属性)、3 个(读写属性,也可删除)和 4 个(读写属性,也可删除,包含文档说明)参数。
3. 定义了get、set、del方法去操作某个或某些实例变量,并用property函数进行这些方法和属性的操作绑定,则对应属性就等同于实例变量一样可以访问,访问时会自动调用相关的get、set、del方法。举例:
我们定义了一个长方形的类的实例:rect=Rectangle(5,4)后,可以通过:print(rect.len)输出长的信息,通过rect.len=10将其长度调整为10。实际上上述操作等同于:
print(rect.getLen())
rect.setLen(10)
上述例子是一个用定义的属性去访问一个私有属性,是一对一的,实际上定义属性可以和类原来定义的实例变量(含私有变量)进行一对多的访问,可以对定义的属性经过运算去改变多个实例变量,因为都是通过set方法去赋值,至于赋值给谁、怎么赋值是set方法来决定的。
4. 如果property定义属性对应的内部实例变量是外部可以访问的,对实例变量的访问是不会触发这些方法的。如果上述案例中self.__length(当然self.__length无法直接访问,但如果是self.length呢)可以从外部赋值,则是直接进行实例变量赋值,不会执行相关set方法。
三、 property函数来定义实例属性的优点
1. 使用property定义实例属性,把通过显示地调用诸如get、set类的方法访问实例变量改成了实例属性的使用和赋值,这样可以有效提高代码的可读性和简洁性,同时还能确保访问逻辑的正确;
2. 在特定场景下,如果历史代码中的实例变量使用直接访问方式使用,但由于业务要求,对该属性需要增加特定访问逻辑,按照常规实现方式需要将所有变量访问改成get、set方法,需要修改大量代码并进行大量测试,而使用property则可以轻松的解决个问题,它可以将原实例变量改名,加上相应的原实例变量需要增强访问逻辑控制的代码的访问方法,然后使用property定义成原实例变量的名字就可以简单实现上述要求。
本节对在类中使用property函数定义一个可供外部简便访问的实例属性的语法进行了说明和解释,需要注意的是这个新定义的属性的读写访问都会通过内部的方法进行,这样简化了属性访问特别是赋值和删除的方法,同时又保证了数据访问的逻辑。下节将结合详细的案例进行进一步介绍。
老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。
欢迎大家批评指正,谢谢大家关注!
第7.23节 Python使用property函数定义属性简化属性访问的代码实现的更多相关文章
- Python使用property函数定义的属性名与其他实例变量重名会怎么样?
首先如果定义的属性名与该属性对应的操作方法操作的实例对象同名就会触发无穷的递归调用,相关部分请参考<Python案例详解:使用property函数定义与实例变量同名的属性会怎样?> 但如果 ...
- Python使用property函数定义属性访问方法如果不定义fget会怎么样?
我们知道Python使用property函数定义属性访问方法时的语法如下: 实例属性=property(fget=None, fset=None, fdel=None, doc=None) 而是要@p ...
- Python使用property函数和使用@property装饰器定义属性访问方法的异同点分析
Python使用property函数和使用@property装饰器都能定义属性的get.set及delete的访问方法,他们的相同点主要如下三点: 1.定义这些方法后,代码中对相关属性的访问实际上都会 ...
- 第7.25节 Python案例详解:使用property函数定义与实例变量同名的属性会怎样?
第7.25节 Python案例详解:使用property函数定义与实例变量同名的属性会怎样? 一. 案例说明 我们上节提到了,使用property函数定义的属性不要与类内已经定义的普通实例变量重 ...
- 第7.24节 Python案例详解:使用property函数定义属性简化属性访问代码实现
第7.24节 Python案例详解:使用property函数定义属性简化属性访问代码实现 一. 案例说明 本节将通过一个案例介绍怎么使用property定义快捷的属性访问.案例中使用Rectan ...
- 第11.23节 Python 中re模块的搜索替换功能:sub及subn函数
一. 引言 在<第11.3节 Python正则表达式搜索支持函数search.match.fullmatch.findall.finditer>重点介绍了几个搜索函数,除了搜索,re模块也 ...
- 第11.15节 Python正则表达式转义符定义的特殊序列
一. 引言 在前面<第11.13节 Python正则表达式的转义符"\"功能介绍>介绍了正则表达式转义符'\',只不过当时作为转义符主要是用于在正则表达式中表示元字符自 ...
- python简单的函数定义和用法实例
python简单的函数定义和用法实例 这篇文章主要介绍了python简单的函数定义和用法,实例分析了Python自定义函数及其使用方法,具有一定参考借鉴价值,需要的朋友可以参考下 具体分析如下: 这里 ...
- python学习7—函数定义、参数、递归、作用域、匿名函数以及函数式编程
python学习7—函数定义.参数.递归.作用域.匿名函数以及函数式编程 1. 函数定义 def test(x) # discription y = 2 * x return y 返回一个值,则返回原 ...
随机推荐
- 【SpringBoot】05.SpringBoot整合Listener的两种方式
SpringBoot整合Listener的两种方式: 1.通过注解扫描完成Listener组件的注册 创建一个类实现ServletContextListener (具体实现哪个Listener根据情况 ...
- Core WebApi项目快速入门(二):Filter详解
Core的核心是DI,面向AOP的编程方式.在.NetCore中AOP的实现很大程度上依赖于Filter.下面就Core WebApi中的Filter进行举例. 其中鉴权中心我个人认为是比较重要的概念 ...
- 基于gin的golang web开发:mysql增删改查
Go语言访问mysql数据库需要用到标准库database/sql和mysql的驱动.标准库的Api使用比较繁琐这里再引入另一个库github.com/jmoiron/sqlx. go get git ...
- 经典c程序100例==31--40
[程序31] 题目:请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续 判断第二个字母. 1.程序分析:用情况语句比较好,如果第一个字母一样,则判断用情况语句或if语句判断第二个字 ...
- Mysql 日期-字符串转换。
mysql的字符串和日期类型的转换. 1.now()和curdate()的区别: now():datetime类型. mysql> select now(); +---------------- ...
- JavaScript封装一个函数效果类似内置方法concat()
JavaScript封装一个函数效果类似内置方法concat() 首先回忆concat()的作用: concat() 方法用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个 ...
- ngx ------ngx_cache_manager_process_cycle
static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) {----------------------- ...
- Go知识点记录
1.go中 堆的实现:https://ieevee.com/tech/2018/01/29/go-heap.html#3-containerheap%E5%8F%AF%E4%BB%A5%E7%94%A ...
- wait函数与waitpid函数(僵尸进程)
当子进程退出时,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程.它只保留最小的一些 ...
- js-根据日期获取本年所有周日
/** * 方法 描述 Date() 返回当日的日期和时间. getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31). getDay() 从 Date 对象返回一周中的某一天 ( ...