Home > front end >  Inheritance for dynamically generated classes
Inheritance for dynamically generated classes

Time:07-05

Contiuing from this post: Dynamically creating a class from file, type(name, bases, dict) can be used to dynamically create a class with name name, with base classes bases, and attributes dict.

I have classes such as:

class City:
    def __init__(self):
        self.name = 0
class Building:
   def __init__(self):
       self.number = 100

I want to create a new class from a string (for ex. "School"), which inherits from the above classes. I have done:

School = type("School", (City, Building), {"school_name": "abc"}
s = School()

hasattr(s, "school_name") gives True. However, hasattr(s, "name") gives False.

How can I make sure that:

  1. My dynamically generated class School inherits the attributes of its base class(es)?
  2. How can I add additional attributes to the class School after already creating the class School = type("School", (Building, Home), {"school_name": "abc"}? (Suppose I want to add two new attributes (address, pincode) to the class later on in my script - can I do that?)

CodePudding user response:

When you create a class dynamically you can also pass methods, "constructor" __init__ included.

For a class with single parent:

# methods & attrs
d = {"school_name": 'abc',
     '__init__': lambda self, *args, **kwargs:
        super(type(self), self).__init__(*args, **kwargs)}

# dynamic class
School = type("School", (City,), d)

# instance
s = School()

print(hasattr(s, 'name'))
#True
print(s.school_name)
#abc

For a class with two parents:

d = {"school_name": 'abc',
     '__init__': lambda self, *args, **kwargs:
        (City.__init__(self, *args, **kwargs),
        Building.__init__(self, *args, **kwargs))[0]
    }

School = type("School", (City, Building), d)
s = School()

print(hasattr(s, 'name'))
#True
print(hasattr(s, 'number'))
#True

The __init__ is called explicitly for each parent. For more complex stuffs I recommend to write a classical function instead of lambdas.

For a class with two parents, base class-free version:

d = {"school_name": 'abc',
     '__init__': lambda self, *args, **kwargs:
     [cls.__init__(self, *args, **kwargs) for cls in type(self).__bases__][0]
    }

NOTE if dealing with multiple inheritance where parents classes have different signatures (so the parameters of __init__) it could be a big mess if don't pay attention to *args & **kwargs!

CodePudding user response:

City’s init method gets override by Building’s init method try

hasattr(s, ‘number’)

and it should return True.

Define your class as

class City:
    name = 0
 
class Building:
    number = 100

This way attributes can be inherited.

For the second question, not sure about what you are asking for, but try

School.address = ‘foo’
School.pincode = ‘bar’
  • Related