【问题标题】:python __getattribute__ RecursionError when returning class variable attribute返回类变量属性时python __getattribute__ RecursionError
【发布时间】:2020-04-24 16:24:42
【问题描述】:

为什么 Foo2 会导致对 __getattribute__ 中的类变量的 getattr 进行无限递归调用,但 Foo 在 __getattr__ 中进行相同调用时工作正常?关于如何让 Foo2 工作的任何建议?

class Foobar(object):
    def __init__(self):
        super().__init__()
        self.bar = 5

    def getbar(self):
        return self.bar


class Foo(object):
    def __init__(self):
        super().__init__()
        self.__foo = Foobar()

    def __getattr__(self, attr):
        return getattr(self.__foo, attr)


class Foo2(object):
    def __init__(self):
        super().__init__()
        self.__foo = Foobar()

    def __getattribute__(self, attr):
        try:
            return getattr(self.__foo, attr)
        except AttributeError:
            super().__getattribute__(attr)


if __name__ == '__main__':
    foo = Foo()
    foo2 = Foo2()
    print(foo.bar, foo.getbar())  # Works as expected
    try:
        print(foo2.bar, foo2.getbar())  # Doesn't work
    except RecursionError:
        print('Why does Foo2 result in RecursionError. How to fix?')

设置:Windows 10、Python 3.7

【问题讨论】:

  • 对于 Foo2,它应该是 __getattr__ 而不是 __getattribute__

标签: python python-3.x recursion getattr getattribute


【解决方案1】:

__getattribute__ 方法被无条件调用以查找对象的所有属性,而不仅仅是那些不存在的属性(__getattr__ 所做的)。当您在其实现中执行self.__foo 时,您会递归,因为__foo 是我们尝试在对象上查找的另一个属性。

为避免此问题,您需要调用父级的 __getattribute__ 方法以在 __getattribute__ 方法中获取您自己的所有属性:

def __getattribute__(self, attr):
    try:
        return getattr(super().__getattribute__("_Foo__foo"), attr)
    except AttributeError:
        super().__getattribute__(attr)

请注意,我必须手动将名称修改应用于__foo 属性,因为我们需要将名称作为字符串传递给super().__getattribute__。这可能表明你不应该首先进行修改。带有一个前导下划线的名称可能是更好的选择。

【讨论】:

  • 我什至没有想到 self.__foo 正在执行属性查找。这确实解决了问题。我猜__getattr__,就像在 Foo 中一样,可能是更清洁/更安全的选择。
猜你喜欢
  • 2020-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
相关资源
最近更新 更多