理解 __getattribute__

1 投票
1 回答
1687 浏览
提问于 2025-04-18 02:11
class Shadow(object):
    pass

class Test(object):
    a = 1
    b = 2

    _shadow = Shadow()

    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self._shadow, name)
        except: print "not shadowed"
        return object.__getattribute__(self, name)

在上面的代码中,我想实现以下功能:

>>>t = Test()
>>>t.a
1
>>>t._shadow.a = 17
>>>t.a
17
>>>t.b
2

这段代码是可以运行的,但它会打印“M”次“not shadowed”(直到达到递归的深度)。我的问题是,为什么会这样?因为这里不应该有递归,我调用的是 object.__getattribute__,而不是 self.__getattribute__

1 个回答

3

__getattribute__ 是在访问任何属性时都会被调用的,包括访问 self._shadow。但是因为你重写了 __getattribute__,所以访问 self._shadow 时会导致无限循环。

解决这个问题的方法是使用 object.__getattribute__,或者更好的是,使用 super(Test, self).__getattribute__ 来获取 _shadow 属性:

class Test(object):
    a = 1
    b = 2

    _shadow = Shadow()

    def __getattribute__(self, name):
        shadow = super(Test, self).__getattribute__('_shadow')
        try:
            return getattr(shadow, name)
        except AttributeError:
            print "not shadowed"
        return super(Test, self).__getattribute__(name)

在访问影子对象的属性时,不需要使用 object.__getattribute__。不要像抓宝可梦那样处理异常(你不想捕捉所有的);在这里只捕捉特定的 AttributeError 异常。

示例:

>>> t = Test()
>>> t.a
not shadowed
1
>>> t._shadow.a = 42
not shadowed
>>> t.a
42

注意,这里访问 t._shadow 也会触发 'not shadowed' 的消息,因为它会经过 __getattribute__ 的处理。

撰写回答