Python Metaclasses: Control How Classes Are Created
You already know that classes create objects. But have you ever wondered — what creates the classes themselves? In Python, the answer is metaclasses.
Think of it like a factory analogy. A car factory produces cars. But who builds the car factory? A factory factory. That's exactly what a metaclass is — a class that builds other classes. It controls the rules and structure every class must follow.
Metaclasses are one of Python's most powerful features. Frameworks like Django, SQLAlchemy, and Flask use them behind the scenes to create elegant APIs. After this tutorial, you'll understand how they work and when to reach for them.
What Is type() Really Doing?
You've probably used type() to check what kind of object something is. But type() has a secret second life — it's also the default metaclass for every class in Python.
Every time you write a class statement, Python uses type() behind the scenes to create that class object. You can even create classes manually with type():
The three arguments to type() are:
() means inherit from object)How Do You Write a Custom Metaclass?
A custom metaclass is just a class that inherits from type. You override __new__ to control how the class object itself gets created. This runs before the class even exists.
Notice the metaclass=UppercaseMeta keyword in the class definition. This tells Python: "Don't use the default type to build this class — use UppercaseMeta instead."
The __new__ method in a metaclass receives four arguments:
mcs instead of cls)Can Metaclasses Enforce Rules on Classes?
One of the most practical uses of metaclasses is validation. You can enforce that every class built with your metaclass follows certain rules — like requiring a docstring, or mandating specific methods.
Is There a Simpler Alternative to Metaclasses?
Python 3.6 introduced __init_subclass__, a hook that runs every time a class is subclassed. It covers many use cases that previously required a full metaclass — with much simpler code.
The __init_subclass__ hook is called on the parent class whenever a new child class is created. You can even accept keyword arguments directly in the class definition — no metaclass needed.
class RegistryMeta(type):
registry = {}
def __new__(mcs, name, bases, ns):
cls = super().__new__(mcs, name, bases, ns)
if bases:
RegistryMeta.registry[name] = cls
return cls
class Plugin(metaclass=RegistryMeta):
passclass Plugin:
registry = {}
def __init_subclass__(cls, **kw):
super().__init_subclass__(**kw)
Plugin.registry[cls.__name__] = clsHow Do Real Frameworks Use Metaclasses?
The most famous metaclass example is Django's model system. When you define a model class, Django's metaclass automatically discovers your fields, creates database table mappings, and adds query methods. Here's a simplified version of that pattern:
Practice Exercises
Use the type() function (not a class statement) to create a class called Counter with:
count initialized to 0increment(self) that increases count by 1 and returns the new valueThen create an instance, call increment() three times, and print the final count.
What does the following code print?
class LogMeta(type):
def __new__(mcs, name, bases, namespace):
print(f'Creating: {name}')
return super().__new__(mcs, name, bases, namespace)
class Base(metaclass=LogMeta):
pass
class Child(Base):
pass
print('Done')Create a metaclass called DocstringRequired that raises a TypeError with the message "Class {name} must have a docstring" if any class using it (excluding the base class) does not have a __doc__ attribute or it is None.
Then create:
Documented that uses the metaclassGoodClass with a docstring 'I have docs'Print GoodClass.__doc__ at the end.
The code below is supposed to auto-register plugins using __init_subclass__, but it has a bug. Fix it so the output shows both plugins registered.
Expected output:
pdf: PDFPlugin
csv: CSVPluginCreate a simplified ORM-style system:
1. A Field class with __init__(self, field_type) that stores the type, and a __repr__ that returns 'Field(<type_name>)' (e.g. 'Field(str)')
2. A metaclass ModelMeta that collects all Field instances into a _fields dict and also stores a _field_names list (sorted alphabetically)
3. A Model base class using the metaclass
4. A Product model with fields: name (str), price (float), quantity (int)
Print Product._field_names.