第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的世界。
欢迎大家批评指正,谢谢大家关注!