I am looking for a solution to allow me to have dynamic inheritance of classes based on certain conditions being met (Python 3.6). Simple enough it seems, but I can't get the attributes of the parent classes to be available in the child class. Everything that depends on self either yields a missing argument error or the attribute doesn't appear. I implemented the solutions to the problem given here and here for dynamic inheritance, yet still run into the same problem with attributes of the child class.
For a sample:
class Parent:
def __init__(self):
self.some_value = 1
def some_function(self):
return self.some_value
def classFactory(parent):
class child(parent):
def __init__(self, parent):
super(child, self).__init__()
parent.__init__(self)
self.some_other_value = 2
def some_other_function(self):
return self.some_value + self.some_other_value
return child
child_class = classFactory(Parent)
child_class.some_value
AttributeError: type object 'child' has no attribute 'some_value'
child_class.some_other_value
AttributeError: type object 'child' has no attribute 'some_other_value'
child_class.some_other_function()
TypeError: some_other_function() missing 1 required positional argument: 'self'
However, if I take the same child construction and remove it from the function definition, it works.
class child(Parent):
def __init__(self, parent):
super(child, self).__init__()
parent.__init__(self)
self.some_other_value = 2
def some_other_function(self):
return self.some_value + self.some_other_value
child_class = child(Parent)
print(child_class.some_value)
# 1
print(child_class.some_other_value)
# 2
print(child_class.some_other_function())
# 3
Why is it that the attributes aren't being inherited in the first case but they are in the second? How can I write the dynamic inheritance to give me the behaviour I expect (as shown in the second case)?
2 Answers 2
It works if I instantiate the child class with the parent argument in return child(parent). This preserves the attributes and methods of both the parent and child.
class Parent:
def __init__(self):
self.some_value = 1
def some_function(self):
return self.some_value
def classFactory(parent):
class child(parent):
def __init__(self, parent):
parent.__init__(self)
self.some_other_value = 2
def some_other_function(self):
return self.some_value + self.some_other_value
return child(parent)
child_class = classFactory(Parent)
print(child_class.some_value)
# 1
print(child_class.some_other_value)
# 2
print(child_class.some_other_function())
# 3
print(child_class.some_function())
# 1
Comments
The most explicit implementation of dynamic inheritance may be implemented with metaclasses:
class A:pass
class B:pass
class Meta(type):
def __new__(cls, name, bases, dct):
bases = (A,) if Meta.condition() else (B,)
return type(name, bases, dct)
@staticmethod
def condition():
# implement condition.
...
class C(metaclass=Meta):
pass
c_instance = C()
print("is C instance of A:")
print(isinstance(c_instance, A))
print("is C instance of B:")
print(isinstance(c_instance, B))
Alternatively, you can define condition function and it as following:
condition = lambda: True
class D(A if condition() else B):
pass
d_instance = D()
print("is D instance of A:")
print(isinstance(d_instance, A))
print("is C instance of B:")
print(isinstance(d_instance, B))
The approach with metaclasses will give you more control over the class creation, so it depends on your needs ...
Parentif usingsuperfunction.super.__init__andparent.__init__?