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
How to Draw Intersecting Planes
How Did Python Implement the Built-In Function Pow()
Run Command and Get Its Stdout, Stderr Separately in Near Real Time Like in a Terminal
Keyerror: 'Tcl_Library' When I Use Cx_Freeze
Find the Recaptcha Element and Click on It -- Python + Selenium
Increment a Python Floating Point Value by the Smallest Possible Amount
How to Use the 'JSON' Module to Read in One JSON Object at a Time
How to Start and Stop a Thread
Python: How to Make the Ansi Escape Codes to Work Also in Windows
How to Compare Multiple Variables to the Same Value
How to Handle Elements Inside Shadow Dom from Selenium
Python Regex Match or Operator
How to Create a Custom Activation Function with Keras
How to Escape Special Characters of a String with Single Backslashes
How to Make File Creation an Atomic Operation
Check If a File Is Not Open Nor Being Used by Another Process