Topic 13.6
Metaclasses and Class Creation
In one line
A class is an object made by another object, type. Knowing how class statements call type(name, bases, namespace) explains metaclasses, but most needs are met more simply by __init_subclass__ and class decorators.
Think of it like this
A cookie cutter and a cookie. The cookie cutter (the class) stamps out cookies (the instances). But someone also had to make the cutter. A machine that makes cookie cutters is a metaclass. In Python the machine that makes classes is called type, and you can swap it for your own to change how classes get built.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Metaclass
- The class of a class. A class that makes other classes. By default it is
type. - `type(name, bases, namespace)`
- Builds a new class from a name, a tuple of parent classes and a dict of attributes.
- Namespace
- The dictionary of names defined in a class body.
- `__new__`
- The method that creates the object (instance or class) before it is initialised.
- `__init_subclass__`
- A hook called on a base class whenever a subclass is defined.
- Class decorator
- A function applied to a finished class that returns the same or a changed class.
- Registry
- A dictionary that collects classes or functions so they can be looked up by name.
- Plugin
- A class that adds a feature and registers itself so the main program can find it.
Step by step
01A class is an object made by type
type(Dog) is type. And Dog = type("Dog", (), {...}) builds the same kind of class a class statement would. The dictionary holds the methods and attributes; here a lambda (a one-line unnamed function, Topic 5.6) is the speak method.
Dog = type("Dog", (), {"sound": "Woof", "speak": lambda self: self.sound})
print(Dog().speak(), Dog.__name__)
print(type(Dog).__name__)02What a class statement does
Python runs the class body as a function, collecting the names into a namespace dictionary. Then it finds the metaclass (the metaclass= keyword if given, otherwise the most derived metaclass among the types of the bases, otherwise type; if two bases have unrelated metaclasses this is where the conflict error comes from) and calls it with the name, the bases and the namespace.
03Watch the order
The first runnable example prints at each step. You see the metaclass hooks run when the class statement finishes, before any instance exists. Then Base() goes through Meta.__call__, Base.__new__, Base.__init__.
04The simpler tool: __init_subclass__
Plugin.__init_subclass__ runs when class CsvReader(Plugin) is defined, so it can add the new class to a registry. Keyword arguments in the class line, such as name="json", arrive as parameters. (The / in the signature means cls is positional-only, Topic 5.4.) Always call super().__init_subclass__(**kwargs) so cooperating bases work.
class Plugin:
registry = {}
def __init_subclass__(cls, /, name=None, **kwargs):
super().__init_subclass__(**kwargs)
Plugin.registry[name or cls.__name__.lower()] = cls
class CsvReader(Plugin):
pass
class JsonReader(Plugin, name="json"):
pass
print(sorted(Plugin.registry))05Class decorators
A class decorator is just a function called with the finished class. @add_repr here reads the class attributes and attaches a __repr__. You will recognise the shape from function decorators (Topic 9.6) and from @dataclass (Topic 8.8).
06Where frameworks use this
Django and SQLAlchemy models collect the fields you declare in the class body when the class is created. Enum turns your list of names into members. ABCMeta records which abstract methods are missing, so Shape() can refuse to be created. Pydantic and dataclass-like libraries read the class annotations at creation time. A plugin registry for model back-ends or tools in an agent framework is usually __init_subclass__.
07A decision guide
Need to change a class after it is made, or add a method? Use a class decorator. Need to react to subclasses (register, validate)? Use __init_subclass__. Need to change the namespace before the class exists, intercept instance creation, or customise how the class itself behaves with operators and built-ins (len(MyClass), for member in MyClass, MyClass["name"] as Enum does)? Then a metaclass is the right tool, used sparingly. (For generic-style MyClass[int] you do not need one: define __class_getitem__ on the class.)
Try it yourself
- 1
Create a class at run time
Use
typeto build a classCatwith asoundattribute and aspeakmethod, create an instance and call it. Then printtype(Cat)andCat.__mro__. - 2
Register with a different key
In the second example add
class XmlReader(Plugin, name="xml")and print the sorted keys. Then define a class that forgetssuper().__init_subclass__(**kwargs)in a second base class and see which registry misses it. - 3
Reject a bad subclass
Make
__init_subclass__raiseTypeErrorwhen a subclass has nosidesattribute defined in its own body. The error appears when the class is defined, not when it is used, which is exactly when you want it.
Code & diagrams
Expected output
Meta.__new__ builds the class Base
Meta.__init__ finishes the class Base
-- class statement finished --
Meta.__call__ makes an instance of Base
Base.__new__ allocates the instance
Base.__init__ fills it in
Meta Meta type
Woof DogExpected output
['csvreader', 'json']
JsonReader
Point(x=1, y=2)Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Combine two metaclasses
Inherit from two classes that use different metaclasses.
class Meta1(type):
pass
class Meta2(type):
pass
class A(metaclass=Meta1):
pass
class B(metaclass=Meta2):
pass
class C(A, B):
passMyth vs fact
Myth
You need a metaclass to customise class creation.
Fact
__init_subclass__ and class decorators cover most needs. A metaclass is the last resort.
Myth
class is special syntax unrelated to type.
Fact
A class statement is a call to the metaclass (usually type) with the name, bases and the namespace built from the body.
Myth
A metaclass makes instances.
Fact
A metaclass makes classes. The class makes instances. A metaclass __call__ only intercepts the step that makes instances.
Myth
Metaclasses are dead since __init_subclass__ exists.
Fact
They still power ABCMeta, EnumMeta and ORMs, and they are the right tool for things like class-level len() and iteration (as in Enum) or a custom __prepare__ namespace.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
The class body is executed with the namespace returned by
Meta.__prepare__, which can be an ordered or special dict. That is howEnumrejects duplicate names and how some DSLs (small mini-languages built inside Python code) record the order of declared fields. Since 3.6 the default namespace keeps definition order. - ▸
Order at class creation, roughly: body runs,
Meta.__new__, then__set_name__on each descriptor in the namespace, then the base class's__init_subclass__, thenMeta.__init__. If your hooks depend on each other, test the order for your Python version rather than memorising it. - ▸
typing.Protocol,dataclassandPydanticmodels all inspect__annotations__at class creation time. Deferred annotations in 3.14 change when annotations are evaluated, which matters to code that reads them from a metaclass. - ▸
__init_subclass__runs for each subclass, never for the class that defines it, and it runs after the class object exists, so it cannot change the namespace the wayMeta.__new__can; it can still add attributes withsetattr.__set_name__and__init_subclass__together replaced most 2.x-era metaclass uses (six.with_metaclass, ORMs naming their fields).types.new_classandtype(...)build classes at run time, andtypeis its own metaclass (type(type) is type), which is where the chain of 'what made this?' ends. - ▸
Metaclass cost and traps: a metaclass
__call__runs on every instantiation, so keep it tiny; a metaclass__getattr__or__setattr__affects class attribute access (Cls.x), not instance access; andisinstanceandissubclasscan be customised on a metaclass through__instancecheck__and__subclasscheck__, which is howABCMetalets unrelated classes count as virtual subclasses. - ▸
Registering subclasses is a common pattern in AI tooling: model back-ends, tools for an agent, loaders and evaluators are found by name through a registry like the example. The danger is an import-time side effect: a plugin registers only if its module is imported, so import them explicitly.
Remember this
- 1
In Python, a class is an object, and like every object it has a type. The type of an ordinary class is
type.type(5)isint, andtype(int)istype. Sotypeis a class factory:type(name, bases, namespace)creates a new class directly. Aclass Dog: ...statement is a convenient way to run the body into a dictionary (the namespace) and then calltype("Dog", (), namespace). - 2
Creating an instance and creating a class both follow two steps. For instances:
__new__allocates the object, then__init__fills it in. For classes: the metaclass's__new__builds the class object, then its__init__finishes it. WritingCat()callstype(Cat).__call__, which runsCat.__new__andCat.__init__; a metaclass can customise that too through__call__. - 3
A metaclass is a class that inherits from
type, used by writingclass Base(metaclass=Meta). Its__new__(mcls, name, bases, namespace)can read and change the namespace before the class exists (for example, add methods or check for required names). Its__init__runs after the class exists. Subclasses ofBaseuse the same metaclass automatically, since the class's type is inherited. - 4
Metaclasses are powerful and rarely needed. Tim Peters' famous line is that metaclasses are deeper magic than 99 percent of users should worry about. They also conflict: a class cannot have two unrelated metaclasses, which causes
TypeError: metaclass conflictwhen you combine bases from two frameworks. Before reaching for one, use a simpler tool. - 5
**
__init_subclass__** (Python 3.6) is that simpler tool. It is a classmethod on the base class that Python calls every time someone defines a subclass, with the new subclass asclsand any class keyword arguments (class JsonReader(Plugin, name="json")). With it you can register subclasses in a registry or validate them, with no metaclass and no conflict risk. - 6
A class decorator (
@add_reprabove aclass) is another simple tool. It receives the finished class, can change it or wrap it, and returns it. Dataclasses are a class decorator. Choose in this order: class decorator or__init_subclass__first, a metaclass only for what they cannot do (changing the namespace before the class exists, a custom__call__, or__prepare__). Real metaclass users areabc.ABCMeta,enum.EnumMeta, and ORMs such as Django and SQLAlchemy.
Explain it without notes
What is a metaclass, and what is the default one?
Explain the order of __new__, __init__ and __call__ when you create a class and when you create an instance.
When would you use __init_subclass__ instead of a metaclass?
What is a class decorator, and how does it differ from a metaclass?
Practice
Use type() to create a class Cat with a sound attribute and a speak method, then call it.
Write a base class whose __init_subclass__ raises TypeError unless the subclass defines sides in its own body.
Write a class decorator register that appends each decorated class name to a list.
Trade-offs
- ↔
Power versus readability. Metaclasses can do anything at class creation, and nobody reading the code can see what happens without finding the metaclass. Prefer the least powerful tool that works.
- ↔
Import-time work. Code that runs when a class is defined (registries, validation) runs at import. It fails early, which is good, but it slows start-up and hides dependencies on import order.
Done when you can
Done when you can explain that a class is an object created by
type.Done when you can build a class with
type(name, bases, namespace).Done when you can write an
__init_subclass__registry and a class decorator.Done when you can say in what order class-creation hooks run.
Done when you can explain a metaclass conflict and how to avoid it.