I have one object wrapped inside another.
The “Wrapper” accesses the attributes from the “Wrapped” object by overriding __getattr__.
This works well until I need to override an atribute on a sub class, and then access the attribute from the base class using super().
I can still access the attribute directly from __getattr__ but why does super() not work?
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()
According to this, super does not allow implicit calls of "hook" functions such as
__getattr__. I’m not sure why it is implemented this way (there’s probably a good reason and things are already confusing enough since the super object has custom__getattribute__and__get__methods as it is), but it seems like it’s just the way things are.Edit: This post appears to clear things up a little. It looks like the problem is the extra layer of indirection caused by
__getattribute__is ignored when calling functions implicitly. Doingfoo.xis equivalent to(Assuming no
__getattribute__method is defined and x is not infoo.__dict__)However, it is NOT equivalent to
Since super returns a proxy object, it has an extra layer of indirection which causes things to fail.
P.S. The
self.__dict__check in your__getattr__function is completely unnecessary.__getattr__is only called if the attribute doesn’t already exist in your dict. (Use__getattribute__if you want it to always be called, but then you have to be very careful, because even something simple likeif name in self.__dict__will cause infinite recursion.