问题描述
在尝试以几种不同的方式创建描述符时,我注意到一些我试图理解的奇怪行为。以下是我创建描述符的三种不同方式:
>>> class NumericValueOne():
... def __init__(self,name):
... self.name = name
... def __get__(self,obj,type=None) -> object:
... return obj.__dict__.get(self.name) or 0
... def __set__(self,value) -> None:
... obj.__dict__[self.name] = value
>>> class NumericValueTwo():
... def __init__(self,name):
... self.name = name
... self.internal_name = '_' + self.name
... def __get__(self,type=None) -> object:
... return getattr(obj,self.internal_name,0)
... def __set__(self,value) -> None:
... setattr(obj,value)
>>> class NumericValueThree():
... def __init__(self,self.name,value)
然后我在 Foo
类中使用它们,如下所示:
>>> class FooOne():
... number = NumericValueOne("number")
>>> class FooTwo():
... number = NumericValueTwo("number")
>>> class FooThree():
... number = NumericValueThree("number")
my_foo_object_one = FooOne()
my_foo_object_two = FooTwo()
my_foo_object_three = FooThree()
my_foo_object_one.number = 3
my_foo_object_two.number = 3
my_foo_object_three.number = 3
虽然 FooOne
和 FooTwo
在设置和获取值时都按预期工作。 FooThree
抛出以下错误:
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
File "<stdin>",line 7,in __set__
File "<stdin>",in __set__
[PrevIoUs line repeated 497 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
看起来 setattr()
正在调用 __set__()
方法?但是,如果 setattr()
正在修改 obj
__dict__
,为什么要这样做?如果我们使用 internal_name
,为什么这会起作用?
为什么我们需要使用私有变量才能正确使用内置的 getattr()
和 setattr()
方法?此外,这与直接修改 obj
中的 __dict__
有什么不同?
解决方法
但是如果 setattr()
正在修改 obj
__dict__
,为什么要这样做?
setattr
不只是修改__dict__
。它设置属性,就像 x.y = z
一样,对于您尝试设置的属性,“设置此属性”意味着“调用您已经在的设置器”。因此,无限递归。
如果我们使用 internal_name
为什么会这样?
该名称与属性不对应,因此它只获取一个 __dict__
条目。