0

在尝试以几种不同的方式创建描述符时,我注意到一些我试图理解的奇怪行为。以下是我创建描述符的三种不同方法:

>>> 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

在设置FooOneFooTwo获取值时按预期工作。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__类似 in 有什么不同NumericValueOne

4

1 回答 1

4

但是,如果setattr()要修改obj __dict__?

setattr 只是修改__dict__. 它设置属性,就像x.y = z会一样,对于您尝试设置的属性,“设置此属性”意味着“调用您已经在其中的设置器”。因此,无限递归。

如果我们使用,为什么这会起作用internal_name

该名称与属性不对应,因此它只是获取一个__dict__条目。

于 2021-01-26T05:10:46.690 回答