覆盖 __getattr__ 导致递归

Overwriting __getattr__ causing recursion

我正在尝试创建一个包装器 class,然后覆盖 __getattr__,以便将不在包装器 class 中的属性请求传递到内部对象中。下面是一个玩具示例,其中我使用列表作为内部对象 -

class A(object):
    def __init__(self):
        pass

    def __getattr__(self, name):
        print 'HERE'
        return getattr(self.foo, name)

    @property
    def foo(self):
        try:
            return self._foo
        except:
            self._foo = [2, 1]
            return self._foo 

我想做类似的事情

 a = A()
 a.sort()  # initializes and sorts _foo 
 print a.foo

打印 [1, 2]

最后,我需要 _foo 在第一次调用 foo 或有人试图从 A() 中获取不在 [=18= 中的属性时进行初始化].不幸的是,我正在进行某种递归并且 HERE 被打印了很多次。我想要的可能吗?

这个

return getattr(self.foo, name)

实际上是:

foo = self.foo
return getattr(foo, name)

现在self.foo实际调用这个:

try:
   return self._foo

,因为你的 class 定义了 __getattr__ 并且 - 至少第一次调用 self.foo - 没有 _foo 属性,调用 self.__getattr__("_foo"),调用 self.foo,等等等等......

简单的解决方案:确保 self._foo 之前定义(即在初始化程序中),而不是试图在 foo() 中定义它。

你也可以在实例的字典中测试 _foo 的存在,但是如果 _foo 也是一个计算属性,那将破坏继承——这是否是一个问题取决于上下文和具体用例。

@property
def foo(self):
    if '_foo' not in self.__dict__:
        self._foo = [2, 1]
    return self._foo 

注意:我假设您将 foo 设为计算属性以允许 _foo 的延迟初始化,否则它毫无意义。如果是这种情况,您也可以非常简单地在初始化程序中使用标记值创建 _foo(通常是 None,除非 None 是此属性的有效值)并给它它在 foo().

中具有真正的价值

您需要先将 _foo 设置为某种值,即使它不是真实值。像这样:

class A(object):
    _foo = None

    def __init__(self):
        pass

    def __getattr__(self, name):
        print 'HERE'
        return getattr(self.foo, name)

    @property
    def foo(self):
        if self._foo is None:
            self._foo = [2, 1]
        return self._foo