Reputation: 5039
I have a base class which has 2 attributes which itself are from another class. See the code below
class Base(object):
def __init__(self, obj1, obj2):
self.obj1 = obj1
self.obj2 = obj2
def __getattribute__(self, name):
#import pdb; pdb.set_trace()
if name == 'obj1':
obj = object.__getattribute__(self, name) #self.obj1.value
return object.__getattribute__(obj,'value')
class Temp(object):
def __init__(self, value, type):
self.value = value
self.type = type
def __getattribute__(self, name):
#if name == 'value':
# return object.__getattribute__(self, name)
if name == 'type':
return object.__getattribute__(self, name)
if __name__ == "__main__":
temp_obj1 = Temp(45, type(45))
temp_obj2 = Temp('string', type('string'))
base_obj = Base(temp_obj1, temp_obj2)
print base_obj.obj1
print base_obj.obj1.type
and its output:-
45
Traceback (most recent call last):
File "getattr.py", line 29, in <module>
print base_obj.obj1.type
AttributeError: 'int' object has no attribute 'type'
Basically what I am trying to achieve is I don't have to call base_obj.obj1.value
to get the value
attribute of obj1
but calling base_obj.obj1
will give the desired result. But at the same time I am be able to call some function or property of obj1
like base_obj.obj1.type
or base_obj.obj1.some_method()
But as you can see I am getting the error. How can I achieve the desired functionality
Upvotes: 0
Views: 1582
Reputation: 251365
If I understand your question right, you can't do what you're trying to do, and what's more, you really shouldn't. Whatever base_obj.obj1
is, base_obj.obj1.type
will get the type
attribute of that, because base_obj.obj1.type
means (base_obj.ob1).type
--- that is, it evaluates the obj1
attribute first. There is no way to make base_obj.obj1
return one thing, but have the base_obj.obj1
part of base_obj.obj1.type
be something different. At the time the lookup of obj1
happens, you do not know whether another attribute lookup is going to take place later.
There are good reasons for this. It would be very confusing if these gave different results:
# 1
x = base_obj.obj1.type
# 2
tmp = base_obj.obj1
x = tmp.type
If you want to get the value
attribute, get the value
attribute. If you want to be able to use obj1
in various situations as if it were its value attribute, you may be able to achieve what you want by overloading various operations on obj1
(so that, e.g., base_obj.obj1 + 2
works).
Upvotes: 1