19

我将一个对象包裹在另一个对象中。“Wrapper”通过覆盖来访问“Wrapped”对象的属性__getattr__。这很好用,直到我需要覆盖子类的属性,然后使用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()
4

1 回答 1

15

据此, super 不允许隐式调用“钩子”函数,例如__getattr__. 我不确定为什么要以这种方式实现(可能有一个很好的理由,而且事情已经很混乱了,因为超级对象有自定义__getattribute____get__方法),但看起来事情就是这样。

编辑:这篇文章似乎把事情弄清楚了一点。看起来问题是__getattribute__隐式调用函数时忽略了额外的间接层。做foo.x相当于

foo.__getattr__(x)

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

foo.__getattribute__('__getattr__')(x)

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

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

于 2012-08-21T03:31:14.487 回答