I am using Python, and I have an interface (a class that only defines the methods signature), that is implemented by two other classes. Now I am adding another wrapper class that implement the interface/base-class, but is actually getting one of the other classes and this wrapper class in most cases just calls one of the two classes. I would like to do some Python magic to avoid defining all methods only the one that I really change.
Here is an example:
class SomeInterface(object):
def do_1(self):
raise Exception("please implement")
def do_2(self):
raise Exception("please implement")
def do_3(self):
raise Exception("please implement")
class Goo(SomeInterface):
def do_1(self):
print("I am goo 1")
def do_2(self):
print("I am goo 2")
def do_3(self):
print("I am goo 3")
class Foo(SomeInterface):
def do_1(self):
print("I am foo 1")
def do_2(self):
print("I am foo 2")
def do_3(self):
print("I am foo 3")
class WrappingInterface(SomeInterface):
def __init__(self, inf: SomeInterface):
self._inner = inf
def do_1(self):
self._inner.do_1()
def do_2(self):
self._inner.do_2()
def do_3(self):
self._inner.do_2()
print("And then doing something else")
Basically, instead of writing do_1 and do_2 in the wrapper class, I would like to do some magic and be able to only write the relevant code.
I tried to implement it using Mixin, but it did not work. Maybe decorator can do it, but I am not sure how.
CodePudding user response:
I don't really understand why do you want to do it like that way. You can inherit your WrappingInterface
from the child class (Eg.: from Foo
):
Code:
class WrappingInterface(Foo):
def do_3(self):
super().do_3()
print("And then doing something else")
test = WrappingInterface()
test.do_1()
test.do_2()
test.do_3()
Output:
>>> python3 test.py
I am foo 1
I am foo 2
I am foo 3
And then doing something else
But if you really needed to extend the base classes then you can do it like this:
Dynamically extend base classes:
class WrappingInterface(SomeInterface):
def __init__(self, inf: SomeInterface):
self._inner = inf
def do_3(self):
self._inner.do_3()
print("And then doing something else")
WrappingInterface = type("WrappingInterface", (Foo,), dict(WrappingInterface.__dict__))
test = WrappingInterface(Foo())
test.do_1()
test.do_2()
test.do_3()
Output:
> python3 test.py
I am foo 1
I am foo 2
I am foo 3
And then doing something else
Or you can do everything inside your class (It's a little hacky but it works).
Code:
class WrappingInterface(SomeInterface):
def __init__(self, inf: SomeInterface):
self._inner = inf()
methods = [method for method in dir(inf) if not method.startswith('__')
and callable(getattr(inf, method))]
for method in methods:
if method in self.__class__.__dict__:
continue
setattr(WrappingInterface, method, getattr(inf, method))
def do_3(self):
self._inner.do_3()
print("And then doing something else")
test = WrappingInterface(Foo)
test.do_1()
test.do_2()
test.do_3()
Output:
>>> python3 test.py
I am foo 1
I am foo 2
I am foo 3
And then doing something else
Note:
I recommend to check the Abstract Base Classes
in Python to do a "real" Abstraction. Reference: https://docs.python.org/3/library/abc.html