Skip to content
advanced Phase 17 · Python Metaprogramming

Metaclasses

Control class creation with metaclasses and __new__.

1h 15m
0 problems
Topic Progress 0%

How Classes Are Created

How Classes Are Created

class X(Base) is not just a block of code — Python performs:

  1. metaclass = most_derived_type(Base) (or type when no base defines one)
  2. namespace = Meta.__prepare__("X", (Base,)) — the per-class namespace (a dict by default)
  3. The class body executes into that namespace (__annotations__ included)
  4. Meta.__new__(Meta, "X", (Base,), namespace) builds the class object
  5. Meta.__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?

Question 1 options

2. When does a metaclass conflict error occur?

Question 2 options

3. Which is usually the lighter alternative to a metaclass for reacting to subclass creation?

Question 3 options

Flashcards

Question

Class creation order

Answer

__prepare__ → body → Meta.__new__ → Meta.__init__ — this is how class X(stmt) executes.

Question

metaclass keyword

Answer

class X(metaclass=M): picks M; M must derive from every base’s metaclass or TypeError follows.

Question

__init_subclass__

Answer

Parent hook called on each subclass creation — the metaclass-lite for registries/hooks.

Question

ABCMeta enforcement

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