How to Dynamically Create Derived Classes from a Base Class

How can I dynamically create derived classes from a base class

This bit of code allows you to create new classes with dynamic
names and parameter names.
The parameter verification in __init__ just does not allow
unknown parameters, if you need other verifications, like
type, or that they are mandatory, just add the logic
there:

class BaseClass(object):
def __init__(self, classtype):
self._type = classtype

def ClassFactory(name, argnames, BaseClass=BaseClass):
def __init__(self, **kwargs):
for key, value in kwargs.items():
# here, the argnames variable is the one passed to the
# ClassFactory call
if key not in argnames:
raise TypeError("Argument %s not valid for %s"
% (key, self.__class__.__name__))
setattr(self, key, value)
BaseClass.__init__(self, name[:-len("Class")])
newclass = type(name, (BaseClass,),{"__init__": __init__})
return newclass

And this works like this, for example:

>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass

I see you are asking for inserting the dynamic names in the naming scope --
now, that is not considered a good practice in Python - you either have
variable names, known at coding time, or data - and names learned in runtime
are more "data" than "variables" -

So, you could just add your classes to a dictionary and use them from there:

name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)

And if your design absolutely needs the names to come in scope,
just do the same, but use the dictionary returned by the globals()
call instead of an arbitrary dictionary:

name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)

(It indeed would be possible for the class factory function to insert the name dynamically on the global scope of the caller - but that is even worse practice, and is not compatible across Python implementations. The way to do that would be to get the caller's execution frame, through sys._getframe(1) and setting the class name in the frame's global dictionary in its f_globals attribute).

update, tl;dr: This answer had become popular, still its very specific to the question body. The general answer on how to
"dynamically create derived classes from a base class"
in Python is a simple call to type passing the new class name, a tuple with the baseclass(es) and the __dict__ body for the new class -like this:

>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})

update
Anyone needing this should also check the dill project - it claims to be able to pickle and unpickle classes just like pickle does to ordinary objects, and had lived to it in some of my tests.

Python: Dynamically create class while providing arguments to __init__subclass__()

The basic documentation for type does not mention that it accepts an unlimited number of keyword-only arguments, which you would supply through the keywords in a class statement. The only place this is hinted in is in the Data Model in the section Creating the class object:

Once the class namespace has been populated by executing the class body, the class object is created by calling metaclass(name, bases, namespace, **kwds) (the additional keywords passed here are the same as those passed to __prepare__).

Normally, you would not use this feature with type exactly because of __init_subclass__:

The default implementation object.__init_subclass__ does nothing, but raises an error if it is called with any arguments.

Since you have overriden the default implementation, you can create your dynamic class as

MyDynamicSubclass = type("MyDynamicSubclass", (MyClass,), {}, my_name="Ellis")

Inheritance for dynamically generated classes

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’

How to choose python base class dynamically?

By the time you call __new__ it is too late to choose the class to instantiate; __new__ is an attribute of the class. Instead you need a trivial factory function:

def my_driver(cls, *args, **kwargs):
class NewThing(cls):
...
return NewThing(*args, **kwargs)

ff = my_driver(webdriver.Firefox)

Another option is to define the base class with an expression:

if ...:
base = webdriver.Firefox
elif ...:
base = webdriver.Chrome
class MyDriver(base):
...

A third option is to skip the class statement and use type directly, although I wouldn't recommend this unless the body of the class statement was going to be empty.

class MyDriver(base):
pass

is equivalent to MyDriver = type('MyDriver', (base,), {}).



Related Topics



Leave a reply



Submit