在 Python 描述符中使用 setattr() 和 getattr()

问题描述

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

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

虽然 FooOneFooTwo 在设置和获取值时都按预期工作。 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__ 条目。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...