Metaclasses: type, __new__, __init_subclass__, and Dynamic Class Generation
- Last updated
- Prerequisites:
- Python Classes and OOP
- Python Data Model
- python
- metaclasses
- type
- init_subclass
- metaprogramming
- class-creation
Read at your depth
The practical view
In Python, `type` is both the default metaclass and a function. You can dynamically create a class using `type(name, bases, dict)`: `MyClass = type('MyClass', (object,), {'x': 10})`. To customize class creation, define a class inheriting from `type`: `class Meta(type): def __new__(cls, name, bases, dct): ...`. In modern Python (3.6+), you can often use `__init_subclass__` instead of full metaclasses for validating or registering subclasses.
The same idea in other frameworks
`class Meta(type): def __new__(cls, name, bases, dct): ...`.Ruby singleton classes / `self.inherited(subclass)` hooks.TypeScript class decorators (`@ClassDecorator`).Rust procedural derive macros generating trait implementations at compile time.Legacy vs modern
Heavy Metaclass vs Modern __init_subclass__ Hook
Metaclasses add complexity and conflict risks; `__init_subclass__` provides simple subclass validation without metaclass overhead.
class ValidateMeta(type): def __new__(cls, name, bases, dct): ... // ❌ Metaclass conflict riskclass BaseModel: def __init_subclass__(cls, **kwargs): ... // ✅ NEW: Clean, no metaclass conflictsInterview gotchas
Context
Interviewers test your deep understanding of multiple inheritance and metaclass resolution.
The mechanical answer
A metaclass conflict occurs when a class inherits from multiple base classes whose metaclasses are not subclasses of one another (e.g. Class A has `MetaA`, Class B has `MetaB`). When defining `class C(A, B):`, Python cannot determine which metaclass to use and throws `TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases`. The fix is to create a common derived metaclass: `class MetaC(MetaA, MetaB): pass`.
Trap
Prefer `__init_subclass__` or class decorators to avoid metaclass conflicts in public libraries.
Context
Checks knowledge of the earliest stage of class definition in Python.
The mechanical answer
`__prepare__(metacls, name, bases)` is called **before the class body is executed**. It returns a mapping object (namespace) in which the class body's code will be executed. By default, it returns a standard `dict`. Before Python 3.6 (when dicts became insertion-ordered), metaclasses used `__prepare__` to return an `collections.OrderedDict` to preserve the exact declaration order of class attributes and fields (essential for ORMs).
Trap
`__prepare__` must be declared as a `@classmethod` or static method on the metaclass.