我有一个对象包裹在另一个对象中。
“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()
答案 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__
这样简单的事情也会导致无限递归。