第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函数定义属性简化属性访问的代码实现的更多相关文章

  1. Python使用property函数定义的属性名与其他实例变量重名会怎么样?

    首先如果定义的属性名与该属性对应的操作方法操作的实例对象同名就会触发无穷的递归调用,相关部分请参考<Python案例详解:使用property函数定义与实例变量同名的属性会怎样?> 但如果 ...

  2. Python使用property函数定义属性访问方法如果不定义fget会怎么样?

    我们知道Python使用property函数定义属性访问方法时的语法如下: 实例属性=property(fget=None, fset=None, fdel=None, doc=None) 而是要@p ...

  3. Python使用property函数和使用@property装饰器定义属性访问方法的异同点分析

    Python使用property函数和使用@property装饰器都能定义属性的get.set及delete的访问方法,他们的相同点主要如下三点: 1.定义这些方法后,代码中对相关属性的访问实际上都会 ...

  4. 第7.25节 Python案例详解:使用property函数定义与实例变量同名的属性会怎样?

    第7.25节 Python案例详解:使用property函数定义与实例变量同名的属性会怎样? 一.    案例说明 我们上节提到了,使用property函数定义的属性不要与类内已经定义的普通实例变量重 ...

  5. 第7.24节 Python案例详解:使用property函数定义属性简化属性访问代码实现

    第7.24节 Python案例详解:使用property函数定义属性简化属性访问代码实现 一.    案例说明 本节将通过一个案例介绍怎么使用property定义快捷的属性访问.案例中使用Rectan ...

  6. 第11.23节 Python 中re模块的搜索替换功能:sub及subn函数

    一. 引言 在<第11.3节 Python正则表达式搜索支持函数search.match.fullmatch.findall.finditer>重点介绍了几个搜索函数,除了搜索,re模块也 ...

  7. 第11.15节 Python正则表达式转义符定义的特殊序列

    一. 引言 在前面<第11.13节 Python正则表达式的转义符"\"功能介绍>介绍了正则表达式转义符'\',只不过当时作为转义符主要是用于在正则表达式中表示元字符自 ...

  8. python简单的函数定义和用法实例

    python简单的函数定义和用法实例 这篇文章主要介绍了python简单的函数定义和用法,实例分析了Python自定义函数及其使用方法,具有一定参考借鉴价值,需要的朋友可以参考下 具体分析如下: 这里 ...

  9. python学习7—函数定义、参数、递归、作用域、匿名函数以及函数式编程

    python学习7—函数定义.参数.递归.作用域.匿名函数以及函数式编程 1. 函数定义 def test(x) # discription y = 2 * x return y 返回一个值,则返回原 ...

随机推荐

  1. 剑指offer之打印超过数组一半的数字

    问题描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  2. 不断要求用户输入学生姓名,输入q结束.

    while (true) { Console.WriteLine("请输入学生姓名"); string a = Console.ReadLine(); if (a == " ...

  3. leetcode144add-two-numbers

    题目描述 给定两个代表非负数的链表,数字在链表中是反向存储的(链表头结点处的数字是个位数,第二个结点上的数字是十位数...),求这个两个数的和,结果也用链表表示. 输入:(2 -> 4 -> ...

  4. css 实现换肤几种方式

    说起换肤功能,前端肯定不陌生,其实就是颜色值的更换,实现方式有很多,也各有优缺点 一.可供选择的换肤 对于只提供几种主题方案,让用户来选择的,一般就简单粗暴的写多套主题 一个全局class控制样式切换 ...

  5. MFC详解

    MFC的消息响应机制详解: 1.MFC是Windows下程序设计的最流行的一个类库,但是该类库比较庞杂,尤其是它的消息映射机制,更是涉及到很多低层的东西,接下来详细讲解. 2.在讲解MFC的消息响应之 ...

  6. Springboot 完整搭建快速入门,必看!

    前言 手把手教你Springboot微服务项目搭建快速入门,通过本文学习Springboot的搭建快速入门,掌握微服务大致的配置服务,后续将会继续将核心组件引入到项目中,欢迎关注,点赞,转发. Spr ...

  7. 02、Hibernate开发步骤

    1.创建Hibernate配置文件(hibernate.cfg.xml) <?xml version="1.0" encoding="UTF-8"?> ...

  8. 详解Java锁的升级与对比(1)——锁的分类与细节(结合部分源码)

    前言 之前只是对Java各种锁都有所认识,但没有一个统一的整理及总结,且没有对"锁升级"这一概念的加深理解,今天趁着周末好好整理下之前记过的笔记,并归纳为此博文,主要参考资源为&l ...

  9. 探究:nuget工具对不再使用的dll文件的处理策略

    背景介绍 nuget是.net平台有效的包管理工具,相信每个C#开发者对它都不陌生. 本文我们来探究一下nuget对不再使用的dll文件的处理策略,分为如下2个场景: 场景A:包A1.0原来包含New ...

  10. 正则表达式——maltrail工程项目中使用

    1. 正则表达所需语法 \ 正则表达式使用反斜杠字符 ('') 来表示特殊形式或是允许在使用特殊字符时不引发它们的特殊含义. 转义特殊字符(允许你匹配 '*', '?', 或者此类其他) \A 只匹配 ...