在 Python 个描述符中使用 setattr() 和 getattr()
Using setattr() and getattr() in Python descriptors
在尝试以几种不同的方式创建描述符时,我注意到一些我试图理解的奇怪行为。以下是我创建描述符的三种不同方式:
>>> 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, obj, value) -> None:
... obj.__dict__[self.name] = value
>>> class NumericValueTwo():
... def __init__(self, name):
... self.name = name
... self.internal_name = '_' + self.name
... def __get__(self, obj, type=None) -> object:
... return getattr(obj, self.internal_name, 0)
... def __set__(self, obj, value) -> None:
... setattr(obj, self.internal_name, value)
>>> class NumericValueThree():
... def __init__(self, name):
... self.name = name
... def __get__(self, obj, type=None) -> object:
... return getattr(obj, self.name, 0)
... def __set__(self, obj, value) -> None:
... setattr(obj, 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>", line 7, in __set__
File "<stdin>", line 7, 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__
有何不同,如 NumericValueOne
?
But why should it be doing that if setattr()
is modifying the obj
__dict__
?
setattr
不只是修改__dict__
。它设置属性,与 x.y = z
完全一样,对于您尝试设置的属性,“设置此属性”意味着“调用您已经在的 setter”。因此,无限递归。
And why does this work if we use internal_name
?
该名称与 属性 不对应,因此它只得到一个 __dict__
条目。
在尝试以几种不同的方式创建描述符时,我注意到一些我试图理解的奇怪行为。以下是我创建描述符的三种不同方式:
>>> 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, obj, value) -> None:
... obj.__dict__[self.name] = value
>>> class NumericValueTwo():
... def __init__(self, name):
... self.name = name
... self.internal_name = '_' + self.name
... def __get__(self, obj, type=None) -> object:
... return getattr(obj, self.internal_name, 0)
... def __set__(self, obj, value) -> None:
... setattr(obj, self.internal_name, value)
>>> class NumericValueThree():
... def __init__(self, name):
... self.name = name
... def __get__(self, obj, type=None) -> object:
... return getattr(obj, self.name, 0)
... def __set__(self, obj, value) -> None:
... setattr(obj, 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>", line 7, in __set__
File "<stdin>", line 7, 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__
有何不同,如 NumericValueOne
?
But why should it be doing that if
setattr()
is modifying theobj
__dict__
?
setattr
不只是修改__dict__
。它设置属性,与 x.y = z
完全一样,对于您尝试设置的属性,“设置此属性”意味着“调用您已经在的 setter”。因此,无限递归。
And why does this work if we use
internal_name
?
该名称与 属性 不对应,因此它只得到一个 __dict__
条目。