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.