class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fget(self):
print("Getting ")
return self.age
def fset(self, value):
print("Setting ")
self.age = value
def fdel(self):
print("Deleting")
del self.age
age = property(fget, fset, fdel, "I'm the property.")
if __name__ == "__main__":
p = Person("ankit", 29)
我正在尝试使用property
构造函数来创建描述符。我不想使用property
的修饰符形式。我收到错误提示
RecursionError: maximum recursion depth exceeded while calling a Python object
答案 0 :(得分:2)
导入文件时,方法中的代码将转换为代码对象,但在您实际调用该方法之前,该方法不会执行。在您运行__init__
时,age
已经是您的媒体资源的名称。因此,行self.age = age
会尝试调用fset
。但是随后fset
尝试做self.age = value
,它只是再次调用fset
,等等。
问题在于您在实例中没有名为age
的可见属性,而在类中只有一个描述符。有两种常见的解决方案。
我最常看到的是在_age
上添加一个名为self
的属性。尽管Python中没有隐私,但下划线要礼貌地要求用户不要搞乱它,除非他们想要意外的结果。
在这种情况下,您的课程如下所示:
class Person:
def __init__(self, name, age):
self.name = name
self._age = age
def fget(self):
print("Getting ")
return self._age
def fset(self, value):
print("Setting ")
self._age = value
def fdel(self):
print("Deleting")
del self._age
age = property(fget, fset, fdel, "I'm the property.")
我个人最喜欢做同一件事的方法是实际使用属性描述符遮盖实例属性的事实。请记住,仅当您使用.
表示法(或直接调用__getattr__
)时才会发生阴影。您仍然可以很好地分配给self.__dict__
。这样就可以以不容易看到或访问的方式保存特定于实例的数据,而无需在对象的名称空间中添加任何名称:
在这种情况下,您的课程如下所示:
class Person:
def __init__(self, name, age):
self.name = name
self.__dict__['age'] = age
def fget(self):
print("Getting ")
return self.__dict__['age']
def fset(self, value):
print("Setting ")
self.__dict__['age'] = value
def fdel(self):
print("Deleting")
del self.__dict__['age']
age = property(fget, fset, fdel, "I'm the property.")
答案 1 :(得分:2)
当object.__setattr__()
找到绑定描述符(使用__set__
方法的描述符)时,它将调用该描述符,而不是在实例的__dict__
中设置name:value对-这很明显实际预期的是xD。
因此,就您而言,当您实例化Person
时:
Person("ankit", 29)
Python调用初始化程序:
def __init__(self, name, age):
self.name = name
self.age = age
调用Person.age.__set__(self, age)
,调用fset(self, value)
:
def fset(self, value):
print("Setting ")
self.age = value
调用Person.age.__set__(self, age)
,调用fset(self, value)
:
def fset(self, value):
print("Setting ")
self.age = value
调用Person.age.__set__(self, age)
,调用fset(self, value)
:
def fset(self, value):
print("Setting ")
self.age = value
调用Person.age.__set__(self, age)
,调用fset(self, value)
:
def fset(self, value):
print("Setting ")
self.age = value
调用Person.age.__set__(self, age)
,调用fset(self, value)
:
def fset(self, value):
print("Setting ")
self.age = value
等等等等等...
IOW,property
和基础实例属性不能使用相同的名称,因为property
将完全隐藏实例属性。
通常,人们使用与property
相同名称的实现属性,只是在其前加一个下划线(Python的“保护属性”约定):
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fget(self):
print("Getting ")
return self._age
def fset(self, value):
print("Setting ")
self._age = value
def fdel(self):
print("Deleting")
del self._age
age = property(fget, fset, fdel, "I'm the property.")
答案 2 :(得分:1)
您需要更改property
变量的名称...
错误:
RecursionError:调用Python对象时超出了最大递归深度
这是因为您调用了property
= age
,所以递归发生在fset
这里是一个例子:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fget(self):
print("Getting ")
return self.age
def fset(self, value):
print("Setting ")
self.age = value
def fdel(self):
print("Deleting")
del self.age
my_age = property(fget, fset, fdel, "I'm the property.")
if __name__ == "__main__":
p = Person("ankit", 29)
print(p.my_age)
这将打印:
获取
29