First things first: as other answers advised, be sure to think through this design decision. Creating classes in a loop is a possibly a red flag that your design is flawed. Moving on.
You can do this using metaclasses, or the type
function. In fact, type
is the default metaclass. It is the class of all built-in classes:
>>> print(type(int))
<class 'type'>
...it is the class of the basic object
class:
>>> print(type(object))
<class 'type'>
...type
is even its own class:
>>> print(type(type))
<class 'type'>
...and unless specified otherwise, all classes you create are themselves type
objects:
>>> class MyClass:
pass
>>> print(type(MyClass))
<class 'type'>
All metaclasses - including type
- can be used to create classes. When used this way, type
takes 3 arguments:
- class name (a string)
- a tuple containing the parent classes
- a dictionary containing class attributes/members
Probably the simplest way to accomplish your goal is to first create a dictionary to hold your classes:
Name = {(i + 1): None for i in range(6)}
We will populate the dictionary values using the type
metaclass:
for num in Name:
Name[num] = type(('Name' + str(i + 1)), (object,), {})
We can accomplish all of the above with this one-liner:
Name = {(i + 1): type(('Name' + str(i + 1)), (object,), {}) for i in range(6)}
In the example above we are inheriting from object
and providing no class members, but this can be adjusted as needed.
If you need more customization in your dynamically created classes, a good option is to use a base class with the starting functionality you require:
class BaseMonster:
def method1(self):
# do stuff
Name = {(i + 1): type(('Name' + str(i + 1)), (BaseMonster,), {}) for i in range(6)}
n1 = Name[1]()
n1.method1()
Recall: type
is the default metaclass. However, even more custimization can be accomplished by creating your own custom metaclass. You do this by inheriting a new class from type
:
class MetaMonster(type):
def __new__(mclass, number, bases, dct):
name = 'Name' + str(number + 1)
return super().__new__(mclass, name, (BaseMonter,) + bases, dct)
And use it like this:
Name = {(i + 1): MetaMonster(i, tuple(), {}) for i in range(6)}
n1 = Name[1]()
n1.method1()
Note that you no longer have to provide the BaseMonster
argument, nor do you have to construct the string representing the class name; this is all taken care of in the MetaMonster.__new__
method.