“超级”对象没有调用__getattr__

时间:2012-08-21 02:50:39

标签: python getattr

我有一个对象包裹在另一个对象中。 “Wrapper”通过覆盖__getattr__来访问“Wrapped”对象中的属性。 这很有效,直到我需要覆盖子类的属性,然后使用super()从基类访问该属性。

我仍然可以直接从__getattr__访问该属性,但为什么super()不起作用?

class Wrapped(object):
    def __init__(self, value):
        self.value = value

    def hello_world(self):
        print 'hello world', self.value

class Wrapper(object):
    def __init__(self, obj):
        self.wrapped_obj = obj

    def __getattr__(self, name):
        if name in self.__dict__:
            return getattr(self, name)
        else:
            return getattr(self.wrapped_obj, name)

class Subclass(Wrapper):
    def __init__(self, obj):
        super(Subclass, self).__init__(obj)

    def hello_world(self):
        # this works
        func = super(Subclass, self).__getattr__('hello_world')()
        # this doesn't
        super(Subclass, self).hello_world()

a = Wrapped(2)
b = Subclass(a)
b.hello_world()

1 个答案:

答案 0 :(得分:12)

According to this, super不允许隐式调用“钩子”函数,例如__getattr__。我不确定为什么它以这种方式实现(可能有一个很好的理由,因为超级对象具有自定义的__getattribute____get__方法,所以事情已经足够令人困惑了,但它看起来像这就是事情的方式。

编辑:This post appears to clear things up a little.看起来问题是在隐式调用函数时忽略由__getattribute__引起的额外的间接层。执行foo.x等同于

foo.__getattr__(x)

(假设没有定义__getattribute__方法且x不在foo.__dict__中) 但是,它不等于

foo.__getattribute__('__getattr__')(x)

由于super返回一个代理对象,它有一个额外的间接层,导致事情失败。

P.S。 self.__dict__功能中的__getattr__检查完全没必要。仅当您的dict中尚不存在该属性时,才会调用__getattr__。 (如果您希望始终调用它,请使用__getattribute__,但是您必须非常小心,因为即使像if name in self.__dict__这样简单的事情也会导致无限递归。