How to dynamically create a class?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Python lets you create classes at runtime, which is useful when type definitions depend on configuration, schemas, or plugin metadata that is not known until the program starts. The usual tool is the built-in type constructor, though for many real projects the harder question is not how to do it, but whether a dynamically created class is genuinely better than a normal class or a dataclass.
Create a Class With type
The three-argument form of type creates a new class object from a name, a tuple of base classes, and a dictionary of attributes.
The resulting Person behaves like any other Python class. You can instantiate it, subclass it, inspect it, and call its methods normally.
Use Named Functions Instead of Large Lambdas
You can put lambdas in the attribute dictionary, but named functions are usually a better choice. They give clearer tracebacks, are easier to test, and make the class definition less cryptic.
This matters because dynamic class creation is already harder to read than a normal class statement. If the methods are also anonymous one-liners, the code becomes fragile quickly.
A good rule is:
- keep the dynamic part focused on assembling the class
- keep method bodies as ordinary functions
- avoid hiding business logic inside the
type(...)call itself
That keeps the design understandable even when the class name or field list is determined at runtime.
Build Classes From Runtime Configuration
A common use case is schema-driven object creation. For example, you may receive a list of required fields from a configuration file and want a lightweight model class for each schema.
This approach is useful in small frameworks, adapters, and plugin systems where the field set changes with runtime input.
Dynamic Inheritance and Mixins
You can also choose base classes dynamically. That is helpful when capabilities are optional and configured at runtime.
The mechanism is simple, but the design can become confusing if too many combinations exist. Dynamic inheritance is best when the set of possible bases is small and deliberate.
Consider make_dataclass for Data-Carrying Types
If the generated class is mostly a container for fields, dataclasses.make_dataclass is often more maintainable than raw type.
This gives you an initializer, representation, and comparison behavior without manually wiring every method. It is often the better answer when the dynamic part is just the field list.
Common Pitfalls
The most common mistake is using dynamic classes when a normal class would be clearer. Runtime class creation is powerful, but it increases cognitive load and makes tooling support weaker.
Another issue is treating runtime-generated attributes as if they were validated automatically. If the class is built from external configuration, you still need to validate field names, defaults, and method behavior.
Debugging can also get harder if methods are defined inline with lambdas or if several different classes share the same helper functions without clear naming.
Finally, metaclasses are often mentioned in discussions like this, but they solve a broader class-creation problem. If you only need to create one or two runtime-defined classes, type or make_dataclass is usually enough.
Summary
- Use
type(name, bases, attrs)to create a class dynamically at runtime. - Keep method bodies as normal functions so the generated class stays readable.
- Dynamic classes are useful for schema-driven and plugin-style designs.
- Prefer
make_dataclasswhen the class mainly holds data fields. - Choose dynamic class creation only when the runtime flexibility is worth the added complexity.

