1

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)?

7
  • 2
    What problem are you trying to solve by doing this? There's probably a better way to solve it. Commented Feb 5, 2019 at 0:33
  • I do not believe you need to explicitly call the constructor on Parent if using super function. Commented Feb 5, 2019 at 1:15
  • The errors result from attempting to use the class instead of an instance of that class. Commented Feb 5, 2019 at 1:24
  • why are you calling super.__init__ and parent.__init__? Commented Feb 5, 2019 at 1:26
  • 2
    Anyway, you are getting attribute errors because those are instance atttributes that belong to instances, not the their classes. You never instantiate an instance in your first example. Commented Feb 5, 2019 at 1:27

2 Answers 2

0

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
Sign up to request clarification or add additional context in comments.

Comments

0

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 ...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.