I have a number of classes which are wrapped by other classes to add new functionality.
Unfortunately, the wrapper classes don't implement pass through functions for the classes they are wrapping, so the wrapper cannot be used interchangeably with the original class.
I would like to dynamically create classes that contain the functionality of both the wrapper and the original class.
The idea I had was to create a mix-in class and use a factory to apply it to the existing class to create a new dual use class dynamically. This should allow me to write the mix-in once, and for the mixed class to be used to provide either the original functionality or the enhanced functionality from from the mix-in via one object.
This is the sort of thing I'm after:
class A:
def __init__(self):
self.name = 'A'
def doA(self):
print "A:", self.name
class B(A):
def __init__(self):
self.name = 'B'
def doB(self):
print "B:", self.name
class C(A):
def __init__(self):
self.name = 'C'
def doC(self):
print "C:", self.name
class D:
def doD(self):
print "D:", self.name
class BD(B,D):
pass
def MixinFactory(name, base_class, mixin):
print "Creating %s" % name
return class(base_class, mixin) # SyntaxError: invalid syntax
a, b, c, d, bd = A(), B(), C(), D(), BD()
bd2 = MixinFactory('BD2', B, D)()
cd = MixinFactory('CD', C, D)()
a.doA() # A: A
b.doA() # A: B
b.doB() # B: B
c.doA() # A: C
c.doC() # C: C
bd.doA() # A: B
bd.doB() # B: B
bd.doD() # D: B
bd2.doA() # A: B
bd2.doB() # B: B
bd2.doD() # D: B
cd.doA() # A: C
cd.doC() # C: C
cd.doD() # D: C
The problem is that obviously that you can't just return a class from a function. Ignoring the syntax error though, the above code does show what I'm trying to achieve.
I had a play with the three argument variant of type()
but couldn't get that to work, so I'm not sure if that is the right approach.
I assume that creating a mix-in factory of this type is possible in Python, so what do I need to understand to implement it?
As Niklas R commented, this answer to the question Python dynamic inheritance: How to choose base class upon instance creation? provides the solution to my query, but Ben's answer here provides a better explanation of why.