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

时间:2022-04-08 07:35:33

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

一、    案例说明

我们上节提到了,使用property函数定义的属性不要与类内已经定义的普通实例变量重名,如果是重名会发生什么呢?本案例通过这个例子一是说明重名可能产生的后果,也想说明property定义属性在类内访问会遇到什么情况。

为了直接说明问题,本案例还是以上节的Rectangle为例,不过去掉了大部分属性和方法,只留下了可以说明问题的必要代码。

二、    案例代码

1.    定义类,类体内定义了实例变量self.length,并定义了类的构造方法、setLen、getLen方法;

class Rectangle():
   def __init__(self,length,width): self.width,self.length = width,length
   def setLen(self,length):
       print("execute setLen")
       self.length=length
   def getLen(self):
       print("execute getLen")
       return self.length

2.    通过property定义属性length,这个属性被设置成可读写的,与实例变量self.length变量名相同;

length = property(getLen, setLen,None,'长方形的长')

3.    定义实例对象

rect = Rectangle(5,3)

执行后,我们看到系统不停的输出“execute setLen”,重复很多次后报“RecursionError: maximum recursion depth exceeded while pickling an object”。部分执行截图:

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

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

 

三、    案例问题分析

1.    原因分析

对这个问题老猿初略分析原因如下:

1)    从上述报错信息可以看出,报错是因为定义实例变量执行构造函数对实例变量self.length赋值时触发了setLen方法,而setLen又会执行self.length赋值导致setLen不停递归调用,最终导致资源耗尽才终止;

2)    为什么self.length的赋值会触发setLen调用呢,肯定是因为自定义属性与实例变量同名导致的。但为什么会这样老猿没有明白,详见下面老猿的疑惑。

2.    老猿的疑惑

为什么定义属性与实例变量同名就会触发递归调用?老猿暂时无法深入分析,在这有两个问题老猿没有弄明白:

1)    property定义的实例属性,其定义语句是在类体中执行的,按理来说这个定义的实例属性是类变量,其类型比较特殊,是property类型,但根据这个实例属性的访问情况来看是通过实例访问,并且不同实例对象之间互不干扰的,因此这个实例属性应该不是类变量,这个不知道property是怎么实现的?

2)    第二个问题是property类型主要有什么属性,可以让它和实例变量关联,我们知道它有四个参数,其中三个方法会被property的 getter(), setter()和delete()所使用,但是哪个属性记录了这些方法访问的实例?

本节介绍了使用property定义与实例变量相同的属性,发现这种定义会导致程序触发递归调用而异常退出,这说明:

1、    不能使用property定义与实例变量同名的实例属性;

2、    实例属性定义后任何在类内和类外的访问都会触发相关方法执行,因此在访问该属性时一定要注意,防止出现本例类似的递归调用。

老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。

欢迎大家批评指正,谢谢大家关注!