Deep Engineering
Advanced·Published·3.11 · 3.12 · 3.13 · 3.14·25 MIN

Metaclasses: the six steps of class creation, which show what a metaclass is for and what no longer needs one

A metaclass is the type of a class, and the whole protocol follows from that alone. The order of the steps is scattered across three sections of the documentation; collected into one column it answers every practical question at once — including the one that makes most metaclasses unnecessary.

Full technical treatment

TL;DR

A class has a type too, and that type is type. An object is an instance of its class; a class is an instance of its metaclass. A metaclass governs how classes are created in much the same way a class governs how instances are created. The language has no separate entity for this: to write your own metaclass you subclass type.

Hence the main consequence: Class(...) is a call on an instance of the metaclass, which is why instance creation is intercepted on the metaclass rather than on the class. And creating a class is itself a chain of steps whose order matters more than the list: __set_name__ on descriptors and __init_subclass__ on the parent are called inside the creation of the class object, that is, before the metaclass's __init__, while a class decorator runs after everything else. The real price of a metaclass is also not the one expected: not time, but a metaclass conflict raised for someone who never chose your metaclass.

Beyond that is what separates knowing from having read. There are six steps:

  1. Meta.__prepare__ — hands out the mapping for the body
  2. the class body runs
  3. Meta.__new__ — the class object is created
  4. __set_name__ on descriptors ← inside type.__new__
  5. __init_subclass__ on the parent ← inside type.__new__
  6. Meta.__init__

Steps 4 and 5 happen inside the third, that is, before the sixth. A metaclass by itself costs nothing: a class with an empty metaclass is created in 7.09 µs against 6.98 µs without one. The one thing charged for is intercepting __call__: 223.3 ns per instance against 59.6 (3.13.7). Which is why, since 3.6 (PEP 487), most tasks are solved with __init_subclass__ and __set_name__. A metaclass is still needed when you must intercept the execution of the class body or instance creation.

Where to start
Before this lesson it is enough to understand
  • how a class is declared and how an instance is made from it;
  • that one class can inherit from another;
  • that a class in Python is a value like a number or a string: it can be stored in a variable and passed to a function;
  • that a decorator is a function that receives an object and returns an object.
You do not need to know in advance
  • type as a metaclass, __prepare__, type.__new__, __init_subclass__, __set_name__;
  • descriptors, the method resolution order, metaclass conflicts, PEP 487.

Base: a class has a type too

The word "metaclass" frightens people more than it should, and nearly always because of one skipped step. The step is this: a class has a type too.

For objects this is familiar. Write x = 5 and x has a type, int. Declare class Order and make order = Order(), and order has a type, Order. The question nobody asks: what is the type of Order itself?

The answer is type. A class is an object like a number or a string, and it has a type as well. That type of a class is what a metaclass is.

From there the model fits into two lines, and these are the two to remember:

  • an object is an instance of its class;
  • a class is an instance of its metaclass.

Hence the junior-level answer, sayable in an interview as it stands: a metaclass governs how classes are created in much the same way a class governs how instances are created. A class decides what an object will be like; a metaclass decides what a class will be like.

That level is enough. If an interview asks "what is a metaclass", the answer above is a correct answer rather than a simplified one: it distorts nothing and promises nothing beyond what is there, and there is no obligation to go further. That is not why this lesson is marked advanced. Everything below is about which steps "creating a class" is made of, where each of them can be interfered with, and why in practice interfering is almost never necessary.

Mechanism 1: a class is an instance of its metaclass, and the protocol follows

language contractLanguage guarantee: a class is an object, and its type is the metaclass. The order of the hooks is set by the reference, not by the implementation.

One line checks it — and shows that the chain stops at type:

PYTHON
class Plain:
    pass
 
print(type(Plain))          # <class 'type'>
print(type(type))           # <class 'type'>

Plain is an object. Its type is type. A metaclass is simply a type whose instances are classes; to write one you subclass type. The language has no separate “metaclass” entity at all.

Something non-obvious follows immediately: Class(...) is a call on an instance of the metaclass. That is why instance creation is intercepted by defining __call__ on the metaclass rather than on the class. This is exactly how singletons are made:

PYTHON
class Singleton(type):
    _instances = {}
 
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

Mechanism 2: six steps, and the order matters more than the list

The reference lists the steps briefly.

When a class definition is executed, the following steps occur: MRO entries are resolved; the appropriate metaclass is determined; the class namespace is prepared; the class body is executed; the class object is created.

Data model, metaclasses

And the two most useful hooks are described elsewhere, in a different section — which is exactly why their place in the order usually gets guessed at.

The type.__new__ method collects all of the attributes in the class namespace that define a __set_name__ method; Those __set_name__ methods are called with the class being defined and the assigned name of that particular attribute; The __init_subclass__ hook is called on the immediate parent of the new class in its method resolution order.

Data model, creating the class object

The key part is whose action this is: both hooks are called by type.__new__ itself, which means they happen inside the third step rather than after it.

What follows in practice:

  • __init_subclass__ will not see what the metaclass does in __init__ — that step is still ahead. The metaclass in __init__, on the other hand, already sees the result of both hooks.
  • The name, the bases and the namespace can be changed only up to the third step. After that they stop being arguments and become properties of an existing class.
  • A class decorator runs last, when everything is already in place: "After the class object is created, it is passed to the class decorators included in the class definition."

What "last" means for a class decorator

From "runs last" it is easy to derive "and therefore can do nothing", which is wrong. It receives a finished class object — and with a finished class you can do almost anything. A run of bench/metaclass/decorator_capabilities.py:

__name__ after the decorator                         Renamed
the new attribute is visible                         added by the decorator
the decorator returned another class: its name       Replacement
a class on object: __bases__ = (Base,)               TypeError
a class on Base: __bases__ = (Another,)              Another

Rename it — it can. Add and rewrite attributes — it can. Return an entirely different object in place of the class, so the name in the module binds to that instead — it can do that too. Bases are trickier, but the restriction is not about decorators: assigning __bases__ is not always allowed (on a class inheriting straight from object it raises TypeError), and that is a rule of type itself, not a consequence of when the decorator runs.

The real boundary runs somewhere else — through time, not power:

before type.__new__the finished class
__prepare__: the mapping the body is written intometaclass
the arguments of type.__new__ (name, bases, namespace)metaclass
what __set_name__ and __init_subclass__ will seemetaclass
attributes, the name, replacing the object entirelymetaclassdecorator

The same run prints the order of events, and in it the class body is executed in the mapping from __prepare__ long before the decorator:

__prepare__ supplied its own mapping
the namespace is given 'a'
the namespace is given 'b'
Meta.__new__ sees the names: ['a', 'b']
decorator: the body has already run, the class is assembled

Mechanism 3: what only a metaclass can do

Three things, and all three follow from the order.

First — intercept the execution of the class body. __prepare__ hands out the mapping the body will be written into, and therefore sees each assignment separately. Nothing else can do this: by the time __init_subclass__ runs the body has already executed and only the result is available.

PYTHON
class NoDuplicates(dict):
    def __setitem__(self, key, value):
        if key in self:
            raise TypeError(f"the name {key!r} is defined twice in the class body")
        super().__setitem__(key, value)
 
class StrictMeta(type):
    @classmethod
    def __prepare__(mcls, name, bases, **kwargs):
        return NoDuplicates()

An ordinary class accepts a duplicated name silently — the last assignment simply wins. With this metaclass you get a TypeError while the class is being defined.

Second — intercept instance creation through __call__. This is what singletons, instance caches and substituting the returned object are built on.

Third — substitute the name, the bases or the namespace. All three are arguments to Meta.__new__, that is, to the third step; by the time __init_subclass__ runs — let alone the decorator — the class already exists and it is too late.

Everything else people reach for a metaclass to do — registering subclasses, checking required attributes, giving descriptors their names — is covered by the two hooks from PEP 487.

The row about the name, the bases and the namespace deserves a precise reading. It is about them as arguments of class creation: only a metaclass can slip its own mapping under the body, or substitute the name or the bases before the class is assembled. A finished class a decorator will happily rename — the run above shows it doing so. The boundary between the two tools runs through time, not through power.

Mechanism 4: the boundary of __init_subclass__

The hook is called on the parent when a child is created. The reference compares it with a decorator directly:

This is closely related to class decorators, but where class decorators only affect the specific class they're applied to, __init_subclass__ solely applies to future subclasses of the class defining the method.

Data model, __init_subclass__

The word "future" is the boundary:

PYTHON
class Registry:
    registered = []
 
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Registry.registered.append(cls.__name__)
 
class First(Registry): pass
class Second(Registry): pass
 
print(Registry.registered)      # ['First', 'Second'] — Registry itself is absent

A metaclass, by contrast, fires for the class that named it too: Meta.__new__ runs for the base class exactly as it does for the subclasses. If a registry must include the base class, that is one of the few reasons to take a metaclass.

One more thing: super().__init_subclass__(**kwargs) on the first line is not a formality. Without it the nearest parent's hook runs and every class further along the MRO is skipped — silently, with no error and no warning.

Deeper: what a metaclass actually costs

measured observationbench/metaclass/cost.py, CPython 3.13.7. Measured on one machine; what matters is that the price is paid for intercepting __call__, not for having a metaclass.

Not time. A class with an empty metaclass is created in 7.09 µs against 6.98 µs without one (3.13.7, best of seven runs) — a difference within the noise, and paid once per class rather than per instance.

Time is charged for exactly one thing: intercepting __call__ adds a Python method call to a path that otherwise runs entirely in C. 223.3 ns per instance against 59.6 — 3.7 times, on every creation. The measurement is on an empty class, so the addition here is a constant: on a class that actually does something in __init__ the same overhead weighs noticeably less. A singleton built with a metaclass pays that on every access, including the ones where the object already exists.

The real price is this one:

The most derived metaclass is one which is a subtype of all of these candidate metaclasses. If none of the candidate metaclasses meets that criterion, then the class definition will fail with TypeError.

Data model, determining the appropriate metaclass
TypeError: metaclass conflict: the metaclass of a derived class must be
a (non-strict) subclass of the metaclasses of all its bases

Note where the error appears: in someone else's file, for whoever writes the subclass and never chose your metaclass. All they wanted was to inherit from your class and from something else with a metaclass of its own — ABC, say, or Enum. They can fix it in two ways only: by not inheriting, or by writing a third metaclass that merges the other two.

How to answer in an interview

The short answer: a metaclass is the type of a class. A class is an instance of its metaclass exactly as an object is an instance of its class, and a metaclass governs how classes are created in much the same way a class governs how instances are created. Hence Class(...) calling the metaclass's __call__: the class is its instance.

That is enough for a correct answer. What follows is what you add when the interviewer digs.

If the interviewer digs deeper

On its own a metaclass can do two things nothing else can: intercept the execution of the class body through __prepare__, and intercept instance creation through __call__. The commonest tasks — registering subclasses, validating their fields, giving a descriptor its name — have been done since 3.6 with __init_subclass__ and __set_name__, more cheaply and without a metaclass conflict. That is design advice, not an equality of powers: preparing the namespace, replacing the bases and intercepting instance creation stay with the metaclass alone.

One phrasing that is easy to get wrong out loud concerns the class decorator. "A decorator cannot replace the class" is false: replacing it is exactly what it may do — it is free to return a different object in the class's place, and the name in the module binds to that. Its boundary lies elsewhere: it takes no part in creating the class. The mapping the body ran in, and the arguments of type.__new__, are history by the time it arrives, and it cannot influence what __set_name__ and __init_subclass__ will see. The difference between it and a metaclass is when it intervenes, not how much it can do.

If asked "when did you last write a metaclass", the honest answer is usually "I haven't", and it is the right one. A good sign the question is understood: name the conflict, not the runtime cost, as the price, and add that the one who pays it is someone else's code. And keep the boundary on the measurements: 7.09 against 6.98 µs and 223.3 against 59.6 ns were taken on one machine and on an empty class (3.13.7) — what they carry is not the number but what exactly is being charged for.

Next they ask

Next they ask

Could all of this be done with __init_subclass__ instead?

Short answer

Almost everything usually wanted, yes — and then a metaclass is unnecessary. The boundary is where you need to intervene in the creation of the class itself rather than react to an already-created subclass: __init_subclass__ runs when the class is already assembled.

Next they ask

Does a metaclass slow down working with the class?

Short answer

By itself, no; it charges at class creation, not at attribute access. What slows things down is a specific act, not the presence of a metaclass — and the lesson separates the two by measurement.

Common misconceptions

Claim

Metaclasses are slow

Actually

Creating a class with an empty metaclass takes 7.09 µs against 6.98 without one — a difference within the noise, paid once per class. Time is charged only for intercepting __call__: 223.3 ns per instance against 59.6 (3.13.7), that is, 3.7 times, and that on EVERY creation. The real price of a metaclass is not in time at all but in the metaclass conflict raised in someone else's code.

Claim

__init_subclass__ is simply a convenient replacement for a metaclass

Actually

A replacement in the most common cases, but not a complete one. It does not fire for the class it is declared on — a base class never lands in its own registry. It takes no part in creating the class: the namespace the body runs in, and the arguments of type.__new__, are behind it by the time it is called (changing attributes of the finished class it can do, just as a decorator can). And it does not see the body executing: __prepare__ belongs to metaclasses alone.

Claim

__set_name__ and __init_subclass__ run after the class is finished

Actually

They run INSIDE type.__new__, that is, between the creation of the class object and Meta.__init__. This is written in the reference and can be checked with a counter. Hence the practical answer: __init_subclass__ will not see what the metaclass does in __init__ — while a class decorator, on the contrary, runs after everything.

Claim

A metaclass is the same as a class decorator, only harder

Actually

A decorator applies to exactly the class it is written above: a subclass does not get it, and in the call order for the subclass the decorator does not appear at all. A metaclass is inherited. And the difference between them is not power but time: a decorator receives a finished class — it can rename it, add attributes, even return a different object in its place — but the namespace the body ran in, and the arguments of type.__new__, are history by the time it arrives.

Claim

A metaclass conflict is a rare edge case

Actually

It happens when someone tries to inherit both from your class and from something with a metaclass of its own — which means ABC and Enum, that is, the standard library. And it happens in SOMEONE ELSE'S file, for the author of the subclass: the “metaclass conflict” message goes to them, not to you.

Version history

VersionChangeWhat this means for your code
3.0PEP 3115 introduces __prepare__ and today's metaclass= syntax in place of the __metaclass__ attribute. From this point a metaclass has the one ability nothing else has: intercepting the execution of the class body.
3.6PEP 487: __init_subclass__ and __set_name__ appear. This is the key row of the table — after it most metaclasses no longer need writing. Registering subclasses, checking required attributes and handing a descriptor its name are all solved without a metaclass and without the risk of a conflict.
3.11The lesson's baseline: the order of the six steps, the behaviour of __prepare__, the boundary of __init_subclass__ and the text of the conflict error are the same on 3.11 as on 3.14.7. Verified by running one script on four versions.
3.12The class C[T] syntax arrives (PEP 695) — and the metaclass starts seeing things the class author never wrote. Verified: __prepare__ receives bases of (typing.Generic,) for a class declared with no bases at all, and the namespace gains __type_params__ and __orig_bases__.
3.13The namespace handed to the metaclass gains __firstlineno__ and __static_attributes__. On 3.11 and 3.12 it held exactly __module__, __qualname__ and whatever the body defined. A metaclass that walks the namespace and fails on an unknown key breaks on this upgrade — the only row in the table capable of breaking existing code.

Practice

Two exercises. Answer first, then check against the real output: in both, the right answer comes from a recorded run rather than from an editor.

Practice · predict the output

A base class keeps a registry of its subclasses through __init_subclass__. What does this code print?
class Base:
  registry = []

  def __init_subclass__(cls, **kwargs):
      super().__init_subclass__(**kwargs)
      Base.registry.append(cls.__name__)


class A(Base):
  pass


class B(A):
  pass


print(Base.registry)

Practice · estimate

Creating an instance of an ordinary class against one whose metaclass intercepts __call__. How many times more expensive is the second?
times

Check yourself

Question 1 of 5

In what order are the parent's __init_subclass__ and Meta.__init__ called when a class is created?

What measured this

The numbers in this article come from these scripts. Each one opens from here, together with the record of the run: what it was measured on, what came out, and with what spread.

Sources & further reading

6 SOURCES

  1. Data model — creating a classOfficial documentation. The primary source for the order of the steps, verbatim: «When a class definition is executed, the following steps occur: MRO entries are resolved; the appropriate metaclass is determined; the class namespace is prepared; the class body is executed; the class object is created». The key part is that the body runs AFTER the namespace is prepared and BEFORE the class object is created.https://docs.python.org/3.14/reference/datamodel.html#metaclasses
  2. Data model — what happens inside type.__new__Official documentation. Where the fact that __set_name__ and __init_subclass__ run inside class creation, not after it, comes from: «The type.__new__ method collects all of the attributes in the class namespace that define a __set_name__ method; Those __set_name__ methods are called with the class being defined and the assigned name of that particular attribute; The __init_subclass__ hook is called on the immediate parent of the new class in its method resolution order». The same page on decorators: «After the class object is created, it is passed to the class decorators included in the class definition».https://docs.python.org/3.14/reference/datamodel.html#creating-the-class-object
  3. Data model — determining the metaclass, and the conflictOfficial documentation. The exact wording of the condition behind a metaclass conflict: «The most derived metaclass is one which is a subtype of all of these candidate metaclasses. If none of the candidate metaclasses meets that criterion, then the class definition will fail with TypeError». It also follows from here that the error surfaces when the SUBCLASS is defined.https://docs.python.org/3.14/reference/datamodel.html#determining-the-appropriate-metaclass
  4. Data model — __init_subclass__ and how it differs from a decoratorOfficial documentation. A direct comparison of the two tools, taken into the lesson whole: «This is closely related to class decorators, but where class decorators only affect the specific class they're applied to, __init_subclass__ solely applies to future subclasses of the class defining the method». The word “future” is what explains why the defining class never lands in its own registry.https://docs.python.org/3.14/reference/datamodel.html#object.__init_subclass__
  5. PEP 3115 — Metaclasses in Python 3000PEP. The document that introduced __prepare__ — the one hook giving a metaclass something no other tool has. Author Talin, status Final, Python 3.0. It is here to show that intercepting the execution of the class body is a stated goal, not a side effect of the implementation.https://peps.python.org/pep-3115/
  6. PEP 487 — Simpler customisation of class creationPEP. The document that added __init_subclass__ and __set_name__ in 3.6. Martin Teichmann and Nick Coghlan, Final. This is precisely why most metaclasses no longer need writing: two hooks cover the most common uses without dragging the class into a metaclass conflict.https://peps.python.org/pep-0487/