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()
Python getattr() The getattr() method returns the value of the named attribute of an object. If not found, it returns the default value provided to the function.
What is getattr() used for? Explanation: getattr(obj,name) is used to get the attribute of an object. 6.
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. Doing foo.x
is equivalent to
foo.__getattr__(x)
(Assuming no __getattribute__
method is defined and x is not in foo.__dict__
)
However, it is NOT equivalent to
foo.__getattribute__('__getattr__')(x)
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 like if name in self.__dict__
will cause infinite recursion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With