我花了一些时间来学习Python的属性魔法。但是当我写一个带有小错误的简单案例时,我得到了一个奇怪的结果。这是我的代码:
class PropertyShow(object):
def __init__(self):
self.__num = 90
def setNum(self,value):
self.__num = value
def getNum(self):
return self.__num
def delNum(self):
del self.__num
#num = property(getNum,setNum,delNum)
# I made a mistake here!
__num = property(getNum,setNum,delNum)
class PropertyTwo(object):
def __init__(self):
self.__num = None
@property
def num(self):
"""OK, use a decorator, you can do something here!"""
return self.__num
@num.setter
def num(self,value):
self.__num = value
@num.deleter
def num(self):
del self.__num
one = PropertyShow()
print one.num
two = PropertyTwo()
print two.num
在关键行中,“num = property(getNum,setNum,delNum)”。我将此行改为粗心,现在就像这个“__num = property(getNum,setNum,delNum)”。
此代码的结果:
File "property.py", line 6, in setNum
self.__num = value
RuntimeError: maximum recursion depth exceeded
num
替换为__num
时,为什么会出现这种意外结果?property()
的魔力以及为什么要使用私有变量?* 答案 0 :(得分:4)
行self.__num = value
导致调用属性设置器。
属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性设置器尝试设置self.__num
,这会导致调用属性设置器。属性setter尝试设置self.__num
,这会导致调用属性设置器。
检测到无限递归。
当您的媒体资源 <{1}}时,这显然不会发生。
要明确:Python将行__num
视为self.__num = value
操作码:
STORE_ATTR
>>> import dis
>>> def setNum(self, value):
... self.__num = value
...
>>> dis.dis(setNum)
2 0 LOAD_FAST 1 (value)
3 LOAD_FAST 0 (self)
6 STORE_ATTR 0 (__num)
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
的实现将首先在类上查找数据描述符,并找到您的STORE_ATTR
__num
对象。然后该呼叫有效地转换为:
property
PropertyShow.__num.__set__(self, value)
对象查找配置的setter函数,property
并将其称为PropertyShow.setNum
。这反过来再次调用PropertyShow.setNum(self, value)
,递归从那里开始。