
Metaclasses in Python Explained Without the Headache
Metaclasses have a reputation. Tim Peters famously said they're "deeper magic than 99% of users should ever worry about", and most tutorials respond by either skipping them or burying you in __new__ signatures. The result is that a lot of experienced Python developers use metaclasses every day (every Enum, every ABC, every Django model) without a clear picture of what one is.
The core idea is short: a metaclass is the class of a class. Just as a class controls how its instances are created and behave, a metaclass controls how classes are created and behave. Everything else is detail.
In this post I'll build that idea up step by step: classes as objects, type as the default metaclass, exactly what happens when Python runs a class statement, how to write a metaclass, and a few realistic uses. Then I'll show the simpler tools (__init_subclass__ and class decorators) that have replaced most metaclasses in modern code, so you know when not to write one.
Step 1: Classes Are Objects
In Python, a class is an ordinary object created at runtime. You can pass it around, store it in a dict, and ask for its type:
class Dog:
sound = "woof"
def speak(self) -> str:
return self.sound
d = Dog()
print(type(d), type(Dog), type(type))
print(isinstance(Dog, type))
<class '__main__.Dog'> <class 'type'> <class 'type'>
True
Read that carefully. d is an instance of Dog. Dog is an instance of type. So type is the class that classes are made from: it's the default metaclass. (And type is its own type, which is where the chain stops.)
Built-ins work the same way: type(int) and type(object) are both type.
Step 2: type Can Build Classes Directly
You know type(obj) as "tell me the class of this object". Called with three arguments, type does something else: it creates a new class.
def speak(self) -> str:
return self.sound
Cat = type("Cat", (), {"sound": "meow", "speak": speak})
print(Cat, Cat().speak(), type(Cat))
<class '__main__.Cat'> meow <class 'type'>
The three arguments are the class name, a tuple of base classes, and a dictionary of attributes (the namespace). This is exactly what a class statement does under the hood. The class keyword is a friendlier syntax for calling a metaclass.
Step 3: What a class Statement Actually Does
When Python executes this:
class Widget(Base):
color = "blue"
def render(self) -> str:
return self.color
it goes through these steps:
- Pick the metaclass. Use the
metaclass=keyword if given; otherwise use the metaclass of the base classes (which istypefor normal classes). - Prepare a namespace. Call
metaclass.__prepare__(name, bases)to get a mapping, usually an empty dict. - Run the class body inside that namespace. Every assignment and
defin the body becomes an entry:color,render, and a few extras like__module__and__qualname__. - Create the class. Call
metaclass(name, bases, namespace), which runs the metaclass's__new__and then its__init__. - Bind the name. Assign the resulting class object to
Widgetin the enclosing scope (after applying any class decorators).
Later, when you create an instance with Widget(), that's a call on the class object, which means the metaclass's __call__ runs. type.__call__ is what invokes the class's own __new__ and __init__.
You can watch all of this by writing a metaclass that logs each hook:
class Meta(type):
@classmethod
def __prepare__(mcls, name, bases, **kwargs):
print(f"1. __prepare__ for {name}")
return {}
def __new__(mcls, name, bases, namespace, **kwargs):
user_attrs = sorted(k for k in namespace if not k.startswith("__"))
print(f"3. __new__ creating {name} with {user_attrs}")
return super().__new__(mcls, name, bases, namespace)
def __init__(cls, name, bases, namespace, **kwargs):
print(f"4. __init__ for {name}")
super().__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
print(f"5. __call__: creating an instance of {cls.__name__}")
return super().__call__(*args, **kwargs)
class Widget(metaclass=Meta):
print("2. class body runs")
color = "blue"
def render(self) -> str:
return self.color
w = Widget()
print(w.render())
1. __prepare__ for Widget
2. class body runs
3. __new__ creating Widget with ['color', 'render']
4. __init__ for Widget
5. __call__: creating an instance of Widget
blue
Steps 1 to 4 happen once, when the module is imported and the class statement runs. Step 5 happens every time you create an instance.
A naming note: inside a metaclass, the first parameter of __new__ is the metaclass itself (conventionally mcls or mcs), and the first parameter of __init__ and other methods is the class being made (conventionally cls). The shift by one level is what makes metaclass code look confusing at first.
Metaclasses Are Inherited
Once a class has a metaclass, its subclasses get it too:
class Sub(Widget):
pass
1. __prepare__ for Sub
3. __new__ creating Sub with []
4. __init__ for Sub
type(Sub) is Meta. This is what makes metaclasses powerful for frameworks: put the metaclass on one base class, and every class users derive from it is processed automatically.
Writing a Useful Metaclass: A Plugin Registry
A classic use is collecting every subclass into a registry, so a framework can look up implementations by name:
# plugins.py
class PluginMeta(type):
registry: dict[str, type] = {}
def __new__(mcls, name, bases, namespace, **kwargs):
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
if bases: # skip the base Plugin class itself
key = namespace.get("name", name.lower())
mcls.registry[key] = cls
return cls
class Plugin(metaclass=PluginMeta):
def run(self, text: str) -> str:
raise NotImplementedError
class Upper(Plugin):
def run(self, text: str) -> str:
return text.upper()
class Reverse(Plugin):
name = "rev"
def run(self, text: str) -> str:
return text[::-1]
print(PluginMeta.registry)
print(PluginMeta.registry["rev"]().run("hello"))
{'upper': <class '__main__.Upper'>, 'rev': <class '__main__.Reverse'>}
olleh
Defining a subclass is enough to register it. No decorator to forget, no central list to update.
Other Things Metaclasses Can Do
Control Instance Creation with __call__
Because Widget() calls the metaclass's __call__, a metaclass can change what instantiation means. The common (if overused) example is a singleton:
class Singleton(type):
_instances: dict[type, object] = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Config(metaclass=Singleton):
def __init__(self) -> None:
print("loading config")
self.debug = False
a = Config()
b = Config()
print(a is b)
loading config
True
__init__ runs only once. In practice, a module-level instance (config = Config()) is usually the simpler way to get one shared object in Python, but this shows the hook.
Customise the Namespace with __prepare__
__prepare__ lets you supply the mapping the class body executes in. That means you can observe every assignment as it happens. For example, rejecting a method that's accidentally defined twice (normally the second silently replaces the first):
class NoDuplicates(dict):
def __setitem__(self, key, value):
if key in self and not key.startswith("__"):
raise TypeError(f"{key!r} defined twice")
super().__setitem__(key, value)
class StrictMeta(type):
@classmethod
def __prepare__(mcls, name, bases, **kwargs):
return NoDuplicates()
def __new__(mcls, name, bases, namespace, **kwargs):
return super().__new__(mcls, name, bases, dict(namespace), **kwargs)
class Handlers(metaclass=StrictMeta):
def on_save(self): ...
def on_load(self): ...
def on_save(self): ...
# TypeError: 'on_save' defined twice
__prepare__ is the one hook that has no simpler replacement. If you need to see the class body while it runs, a metaclass is the only way. The standard library's Enum uses this to detect duplicate member names.
Add Methods to the Class Itself
Methods defined on a metaclass are available on the class, but not on its instances:
class Meta(type):
def describe(cls) -> str:
return f"class {cls.__name__}"
class Thing(metaclass=Meta):
pass
print(Thing.describe()) # class Thing
Thing().describe() # AttributeError: 'Thing' object has no attribute 'describe'
That's how len(MyEnum) and for member in MyEnum work: EnumType, the metaclass of Enum, defines __len__ and __iter__ for enum classes. (See Enums in Python for the user-facing side.)
Metaclasses You Already Use
import abc
import enum
print(type(enum.Enum), type(abc.ABC))
<class 'enum.EnumType'> <class 'abc.ABCMeta'>
ABCMetacollects abstract methods when the class is created and blocks instantiation in__call__if any remain. The abc module post covers it.EnumTypeturns class attributes into member singletons, prevents reassignment, and makes the class iterable.- ORMs like Django use a metaclass (
ModelBase) to turn field declarations into database columns and build theobjectsmanager. SQLAlchemy's declarative base has used both metaclass and__init_subclass__-based approaches over its history.
The Modern Alternatives
Most of what people used metaclasses for before Python 3.6 now has a simpler tool. Reach for these first.
__init_subclass__
Python 3.6 added __init_subclass__, a class method on the parent that runs every time a subclass is created. Here's the plugin registry again, with no metaclass:
# plugins.py
class Plugin:
registry: dict[str, type["Plugin"]] = {}
def __init_subclass__(cls, /, name: str | None = None, **kwargs) -> None:
super().__init_subclass__(**kwargs)
Plugin.registry[name or cls.__name__.lower()] = cls
def run(self, text: str) -> str:
raise NotImplementedError
class Upper(Plugin):
def run(self, text: str) -> str:
return text.upper()
class Reverse(Plugin, name="rev"):
def run(self, text: str) -> str:
return text[::-1]
print(Plugin.registry)
{'upper': <class '__main__.Upper'>, 'rev': <class '__main__.Reverse'>}
It's shorter, it doesn't introduce a new type, and keyword arguments in the class statement (name="rev") are passed straight to it. It also works fine alongside other base classes, which metaclasses often don't (see below).
It's also a good place for definition-time validation:
class Command:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if not callable(getattr(cls, "execute", None)):
raise TypeError(f"{cls.__name__} must define execute()")
if not cls.__doc__:
raise TypeError(f"{cls.__name__} needs a docstring for --help")
class Deploy(Command):
"""Deploy the current build."""
def execute(self) -> None: ...
class Broken(Command):
def execute(self) -> None: ...
# TypeError: Broken needs a docstring for --help
Class Decorators
If you only need to process specific classes, not a whole hierarchy, a class decorator is a plain function that receives the finished class and returns it (or a replacement):
def register(registry: dict):
def decorator(cls):
registry[cls.__name__.lower()] = cls
return cls
return decorator
HANDLERS: dict[str, type] = {}
@register(HANDLERS)
class Csv: ...
@register(HANDLERS)
class Json: ...
print(HANDLERS) # {'csv': <class '__main__.Csv'>, 'json': <class '__main__.Json'>}
@dataclass is the best-known class decorator. It reads the class's annotations and generates __init__, __repr__, and friends, all without a metaclass. Decorators are explicit (you can see them on the class) and aren't inherited, which is often what you want. For more on how decorators work in general, see Python Decorators Explained.
__set_name__
If you're tempted to write a metaclass so that attributes know their own names, __set_name__ on the attribute's class already does that. The descriptors post shows it in action.
Why Metaclasses Cause Trouble: Conflicts
A class can have only one metaclass, and it must be compatible with the metaclasses of all its bases. Mixing two unrelated metaclasses fails:
class MetaA(type): pass
class MetaB(type): pass
class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass
class C(A, B): pass
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
The fix is a combined metaclass, class MetaAB(MetaA, MetaB): pass, used as class C(A, B, metaclass=MetaAB). That works when the two metaclasses cooperate, but it's fragile, and it's a real problem when the metaclasses come from two libraries (say, an ORM base class and ABC). This is the biggest practical reason to prefer __init_subclass__, which has no such conflicts.
When Should You Write a Metaclass?
A short decision list:
| You want to... | Use |
|---|---|
| Run code whenever a subclass is defined | __init_subclass__ |
| Validate or register subclasses | __init_subclass__ |
| Modify or wrap one specific class | A class decorator |
| Let an attribute know its own name | __set_name__ |
| Generate methods from annotations | A class decorator (like @dataclass) |
| Observe or control the class body as it executes | A metaclass (__prepare__) |
Change what MyClass() returns for a whole hierarchy | A metaclass (__call__), or a factory function |
Give classes themselves operators or methods (len(MyClass)) | A metaclass |
If your need is in the first five rows, you don't need a metaclass. The last three are where metaclasses are still the right tool, and they mostly come up when you're building a framework or a library others will subclass.
Conclusion
A metaclass is the class of a class. type is the default one, and a class statement is essentially a call to it: prepare a namespace, run the body, then create the class with __new__ and __init__. Instantiating that class later goes through the metaclass's __call__. Write your own metaclass by subclassing type and overriding those hooks.
That's genuinely all there is to it. The headache comes from overuse, not complexity. For registering subclasses, validating definitions, or adding generated methods, __init_subclass__ and class decorators do the job with less code and no metaclass conflicts. Keep metaclasses for the rare cases that need __prepare__, class-level operators, or control over instantiation across a whole hierarchy, and you'll recognise them easily when you meet them inside Enum, ABC, and your ORM.


