See full gist here
Consider the case where we have a simple metaclass that generates the __init__ method for a class
class TestType(type):
def __new__(cls, cname, bases, attrs):
# Dynamically create the __init__ function
def init(self, message):
self.message = message
# Assign the created function as the __init__ method.
attrs['__init__'] = init
# Create the class.
return super().__new__(cls, cname, bases, attrs)
class Test(metaclass=TestType):
def get_message(self):
return self.message
Now this is all good and well to use
test = Test('hello')
assert test.get_message() == 'hello'
But we have problems when subclassing, because if you want to subclass the __init__ method what of course happens is the subclassed method just gets overwritten.
class SubTest(Test):
def __init__(self, first, second):
self.first = first
self.second = second
super().__init__(first + ' ' second)
subtest = SubTest('hello', 'there')
This will obviously give the
TypeError: init() takes 2 positional arguments but 3 were given
The only way I can think to solve this is to create an intermediate class in the __new__ method of the metaclass and make this the base for the class we are creating. But I can't get this to work, I tried something like this
class TestType(type):
def __new__(cls, cname, bases, attrs):
# Dynamically create the __init__ function
def init(self, message):
self.message = message
# If the __init__ method is being subclassed
if '__init__' in attrs:
# Store the subclass __init__
sub_init = attrs.pop('__init__')
# Assign the created function as the __init__ method.
attrs['__init__'] = init
# Create an intermediate class to become the base.
interm_base = type(cname + 'Intermediate', bases, attrs)
# Add the intermediate class as our base.
bases = (interm_base,)
# Assign the subclass __init__ as the __init__ method.
attrs['__init__'] = sub_init
else:
# Assign the created function as the __init__ method.
attrs['__init__'] = init
# Create the class.
return super().__new__(cls, cname, bases, attrs)
But this gives me recursion error
RecursionError: maximum recursion depth exceeded while calling a Python object
TestTypeclass with the originalTestTypedefinition...__init__method and 2) one of the class's parents is already an instance ofTestType. Do you want to insert the defaultinitbetweenSubTest.__init__andTest.__init__?