Reputation: 1068
Context and intentions: I want to use an object m_o
of type My_object
as a way of interfacing with another object called s_o
of type Stubborn_object
. For the sake of easy understanding, they should behave like if My_object
inherited from Stubborn_object
, in the way that calling an attribute that doesn't exist in My_object
should call the attribute in Stubborn_object
.
However, the tricky thing is that I wouldn't be asking this question if I could simply inherit My_object
from Stubborn_object
. It appears that I can't inherit from it, and, for many reasons, I also can't modify the code of the Stubborn_object
class, so I have to use it as it is. Please note that trying to inherit isn't the issue of the question here. I know that other solutions exist for my practical problem, but I really want answers to stay on topic for many reasons. I suspect that other users can have different problems than mine and still be unable to inherit a class. Furthermore, not being able to inherit a class is not the only reason that could make someone read this question. In fact, it's quite a general Python object-oriented problem. I also believe the solution of my problem could be useful in other applications, like custom error handling within the object itself when an attribute is not found, or in thread management to lock the instance as soon as an attribute is called.
In addition to the problem of inheritance, let's suppose that I can't use conditions at higher levels to handle these cases, so everything has to be done inside My_object
instance or its parents. That means that I can't use hasattr(m_o, attribute_name)
to determine if I should call getattr(m_o, attribute_name)
or getattr(s_o, attribute_name)
. This also means that any try/except
blocks and other preconditions must be inside the My_object
class or its parents. The point of this question is not about detecting exceptions when calling an attribute from outside the My_object
instance. A try/catch
block normally has to be outside the My_object
class, and I previously stated that this can't be allowed.
For the sake of clarity and to provide a complete verifiable example, here is a sample code of the Stubborn_object
class. I know that I said I can't inherit from Stubborn_object
and the following code includes an inheritable class. Providing an example of an non-inheritable object would only bring confusion and it would'nt be really helpful to the question anyway, so here is a simple example of an inheritable object. The objective of this is to make an easy to understand question, so please just consider that you can't inherit from it:
class Stubborn_object:
def do_something(self):
print("do_something")
def action_to_override():
print("action_to_override")
def action_a(self):
print("action_a")
def action_b(self):
print("action_b")
Objective: Put it simply, I want my class My_object
to detect all by itself that a lacking attribute has been called and run some instructions instead of throwing an AttributeError
.
Current attempts: Right now, I manually redirect method calls to the Stubborn_object
instance like so (it's successful, but not reliable nor scalable because of the use of hardcoding):
class My_object():
def __init__(self, s_o):
self.stubborn_object = s_o
def action_to_override(self):
# Do stuff. This method "overrides" the Stubborn_object.action_to_override method.
print("Here is stuff getting done instead of action_to_override")
def action_a(self):
return self.stubborn_object.action_a()
def action_b(self):
return self.stubborn_object.action_b()
s_o = Stubborn_object()
m_o = My_object(s_o)
m_o.action_to_override() # Executes Stubborn_object.do_something()
m_o.action_a() # Executes Stubborn_object.action_a()
m_o.action_b() # Executes Stubborn_object.action_b()
Executing this code along with the provided Stubborn_object
code sample should print:
Here is stuff getting done instead of action_to_override
action_a
action_b
As you can see from methods action_a
and action_b
, I have to manually call the Stubborn_object
methods from whithin the methods in My_object
to mimic the attributes of Stubborn_object
. This is ineficient, lacks of robustness and will throw an AttributeError
exception if we attempt to make an action that wasn't included in the My_object
code.
What if I wanted to automatically send method and attribute calls to the Stubborn_object
instance without having to rewrite all of its method and attributes in My_object
? I believe this can be achieved with detecting if a lacking attribute of My_object
instance is called.
Expectations (or sort of): I am open to any solution that allows the My_object
class or its parents to determine if the attribute is lacking or not, all within itself. So I believe I am ready to hear extremely original ideas, so go ahead.
On my part, I believe that something that uses parts of this code is the way to go, but it still lacks the "catch any called attribute" part:
class My_object():
def __init__(self, s_o):
# __init__ stays as it was.
self.stubborn_object = s_o
def action_to_override(self):
# This method also stays as it was.
# Do stuff. This method "overrides" the stubborn_object.action_to_override method.
print("Here is stuff getting done instead of action_to_override")
def run_me_when_method_is_not_found(self, method_name, **kwargs):
print("Method " + method_name + " not in 'My_object' class.")
return getattr(self.stubborn_object, method_name)(**kwargs)
So running those lines with the previous code sample
s_o = Stubborn_object()
m_o = My_object(s_o)
m_o.action_to_override() # Executes Stubborn_object.do_something()
m_o.action_a() # Executes Stubborn_object.action_a()
m_o.action_b() # Executes Stubborn_object.action_b()
will print
Here is stuff getting done instead of action_to_override
Method action_a not in 'My_object' class.
action_a
Method action_b not in 'My_object' class.
action_b
Some similar methods will have to be made for getters and setters, however, the idea stays the same. The thing is that this code lacks the ability to detect that an attribute is missing.
Question: How can I run the run_me_when_method_is_not_found
when the method is not found in My_object
? Especially, how can a My_object
instance detect that the method doesn't exists in its class instead of throwing an AttributeError
exception?
Thanks a lot.
Upvotes: 2
Views: 1234
Reputation: 8550
Seems like overriding __getattribute__
will do exactly what you want: search for attribute in self.stubborn_object
if it is missing in self
. Put it into My_object
class definition:
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError:
return object.__getattribute__(self.stubborn_object, attr)
Upvotes: 3