How Classes Are Created
How Classes Are Created
class X(Base) is not just a block of code — Python performs:
metaclass = most_derived_type(Base)(ortypewhen no base defines one)namespace = Meta.__prepare__("X", (Base,))— the per-class namespace (a dict by default)- The class body executes into that namespace (
__annotations__included) Meta.__new__(Meta, "X", (Base,), namespace)builds the class objectMeta.__init__(cls, name, bases, namespace)finishes setup
type itself is a metaclass — X = type("X", (Base,), {...}) is equivalent to the statement form. Every class is simultaneously an instance of its metaclass and (usually) an instance of type, which is why isinstance(X, Meta) and issubclass(X, Base) can both be true.
Writing a Metaclass
Writing a Metaclass
class Validated(type):
def __new__(mcls, name, bases, ns, **kwargs):
for field_name in ns.get("__annotations__", {}):
if field_name.startswith("_"):
raise TypeError(f"{name}.{field_name} cannot be annotated")
cls = super().__new__(mcls, name, bases, ns, **kwargs)
if hasattr(cls, "registry"):
cls.registry[name] = cls
return cls
def __init__(cls, name, bases, ns, **kwargs):
super().__init__(name, bases, ns, **kwargs) # don't forget this
class Model(metaclass=Validated):
registry: dict = {}
The same slot powers plugin registries: subclasses register the moment the class statement runs. ABCMeta (behind abc.ABC) enforces @abstractmethod at subclass creation — instantiating an incomplete class fails immediately, not at first call.
Pitfalls and Alternatives
Pitfalls and Alternatives
Metaclass conflict. Two unrelated bases with different metaclasses:
TypeError: metaclass conflict: the metaclass of a derived class is the
most derived of its metaclasses
Fix by making one metaclass derive from the other, or restructure.
Prefer simpler tools:
| Need | Simpler tool |
|---|---|
| Run code when a subclass appears | __init_subclass__(cls) (3.6+) |
| Add behavior to one class | decorator |
| Enforce methods on instances | ABCMeta / Protocol |
Metaclasses pay off only for class-wide policy (registries, validation, ORMs like Django models). Cost: they compose badly with libraries that also want a metaclass, confuse readers, and interact subtly with __slots__. Interview angle: explain steps 1–5 of class creation, then justify why __init_subclass__ solved your last need without one.
Quiz
1. What is the default metaclass of a plain class in Python 3?
2. When does a metaclass conflict error occur?
3. Which is usually the lighter alternative to a metaclass for reacting to subclass creation?
Flashcards
Question
Class creation order
Click to reveal answer
Answer
__prepare__ → body → Meta.__new__ → Meta.__init__ — this is how class X(stmt) executes.
Question
metaclass keyword
Click to reveal answer
Answer
class X(metaclass=M): picks M; M must derive from every base’s metaclass or TypeError follows.
Question
__init_subclass__
Click to reveal answer
Answer
Parent hook called on each subclass creation — the metaclass-lite for registries/hooks.
Question
ABCMeta enforcement
Click to reveal answer
Answer
Metaclass behind abc.ABC that rejects instantiation of classes missing abstract methods.
Revision Notes
Key Takeaways
- 1. A class statement is a call: namespace prep, body execution, metaclass __new__/__init__
- 2. Metaclasses enforce policy at class-creation time — registries, validation, abstract enforcement
- 3. Reach for __init_subclass__ or decorators first; metaclasses are the tool of last resort
Interview Tips
- • Recite the five-step class-creation sequence — it separates real understanding from blog-level familiarity
- • When asked about ORMs, tie table/schema registration to metaclass interception of class definitions
Cheat Sheet
class stmt → prepare → body → Meta.new → Meta.init; default meta = type; conflict = unrelated metas; prefer init_subclass for hooks.
Continue Learning
Before You Start
- No prerequisites listed.