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:
- My dynamically generated class
School
inherits the attributes of its base class(es)? - How can I add additional attributes to the class
School
after already creating the classSchool = 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 lambda
s.
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’