Python Class Creation Runs a Defined Hook Sequence
The order of metaclass selection, namespace preparation, class-body execution, __set_name__, __init_subclass__, and decorators.
A Python class statement executes code and passes the resulting namespace through a defined construction protocol. It resolves non-type bases, chooses a metaclass, prepares a namespace, runs the body, creates the class, calls descriptor and subclass hooks, applies decorators, and finally binds the class name.
Knowing that order tells you which hook has access to which information. This article targets Python 3.14.7 and follows the data-model class-creation reference. __set_name__ and __init_subclass__ require Python 3.6 or later.
The metaclass prepares the body namespace
Before the class body runs, Python resolves __mro_entries__ for bases that are not types. It then selects the most-derived metaclass compatible with the explicit metaclass, if any, and all base-class metaclasses. If no candidate is a subtype of every other candidate, class creation raises TypeError for a metaclass conflict.
Python calls the selected metaclass’s __prepare__(name, bases, **keywords) when that method exists. The returned mapping receives assignments made by the body:
class RecordingMeta(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return {"prepared_by": metacls.__name__}
def __new__(metacls, name, bases, namespace, **kwargs):
cls = super().__new__(metacls, name, bases, namespace)
cls.body_names = tuple(namespace)
return cls
class Report(metaclass=RecordingMeta):
format = "json"
assert Report.prepared_by == "RecordingMeta"
assert "format" in Report.body_names
The body runs approximately like exec(body, globals(), namespace). Statements, function definitions, imports, and exceptions behave as executable code. Methods do not close over ordinary names in the class namespace, so a method should read self.format, type(self).format, or Report.format rather than a bare format.
type.__new__ triggers definition-time hooks
When the metaclass ultimately calls type.__new__, Python creates the class object, then calls __set_name__(owner, name) on every class-body value that defines it. After those calls, Python invokes __init_subclass__ through the immediate parent in the new class’s MRO.
events = []
class Field:
def __set_name__(self, owner, name):
self.name = name
events.append(("field", owner.__name__, name))
class Registered:
subclasses = []
def __init_subclass__(cls, *, kind, **kwargs):
super().__init_subclass__(**kwargs)
cls.kind = kind
cls.subclasses.append(cls)
events.append(("subclass", cls.__name__, cls.payload.name))
class Message(Registered, kind="event"):
payload = Field()
assert events == [
("field", "Message", "payload"),
("subclass", "Message", "payload"),
]
The subclass hook sees an initialized descriptor because __set_name__ runs first. Assigning another Field to Message after creation does not call __set_name__ automatically. Call the hook yourself or expose a class API that performs both operations.
Class-definition keywords other than metaclass flow through metaclass operations and then to __init_subclass__. A cooperative hook should consume its own keywords and pass the rest with super().__init_subclass__(**kwargs). The endpoint, object.__init_subclass__, rejects leftover arguments and catches misspellings or unsupported options.
Decorators run after the class exists
After the class object and built-in hooks are complete, Python applies class decorators from the innermost decorator upward. The result of the outermost call is bound to the class name.
def mark(cls):
events.append(("decorator", cls.__name__))
cls.marked = True
return cls
@mark
class Decorated(Registered, kind="command"):
payload = Field()
assert events[-1] == ("decorator", "Decorated")
assert Decorated.marked
A decorator can return a different object, so code in __init_subclass__ runs before the final name binding and cannot see that replacement. Use a decorator for explicit transformation of one declaration. Use __init_subclass__ when a base class owns behavior for all future subclasses.
Use the least powerful hook that fits
__set_name__ lets one class attribute learn its owner and assigned name. __init_subclass__ validates or registers descendants. A decorator makes a visible, per-class transformation. A metaclass controls namespace preparation and class-object construction across a hierarchy.
Metaclasses also create integration costs because multiple bases need compatible metaclasses. PEP 487 added __set_name__ and __init_subclass__ so common definition-time work does not require a metaclass. Start with those narrower hooks. Reach for a metaclass when the job truly needs to affect the namespace before the body runs or the class object while it is being created.