🚀AdvancedMetaprogramming

Metaclasses

Understand how Python creates classes at runtime, write custom metaclasses, and use __init_subclass__ for lightweight hooks.

Overview

In Python, **everything is an object** including classes. A class is an instance of a **metaclass**. The default metaclass is `type`. When Python executes a `class` statement, it calls the metaclass to build the class object. This means you can intercept class creation by writing a custom metaclass that inherits from `type`. You override `__new__` (called before the class exists) or `__init__` (called after) to inspect or modify the class, enforce constraints, auto-register subclasses, inject methods, or validate attributes. Modern Python often prefers `__init_subclass__` (PEP 487, Python 3.6+) for many use cases it's a class method that runs when a subclass is created, with far less boilerplate than a full metaclass. `__class_getitem__` lets you support generic-style syntax (`MyClass[int]`). Metaclasses power many frameworks: Django's ORM models, SQLAlchemy declarative base, Pydantic, and abc.ABCMeta all use metaclasses internally.

Key Points

  • •`type(name, bases, namespace)` is the built-in way to create a class dynamically
  • •A metaclass is a class whose instances are classes; the default is `type`
  • •Set metaclass: `class Foo(metaclass=MyMeta):`
  • •Override `__new__(mcs, name, bases, ns)` in the metaclass to modify the class dict before creation
  • •Override `__init__(cls, name, bases, ns)` to run code after the class object is created
  • •`__init_subclass__(cls, **kwargs)` simpler hook: runs in the parent class when a subclass is created
  • •Metaclass conflict: if two base classes have different metaclasses, you must create a combined metaclass

Examples

type() dynamic class creation

# These two definitions are equivalent

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

# Same using type():
def point_init(self, x, y):
    self.x, self.y = x, y
def point_repr(self):
    return f"Point({self.x}, {self.y})"

DynPoint = type("DynPoint", (), {
    "__init__": point_init,
    "__repr__": point_repr,
})

p = DynPoint(3, 4)
print(p)          # DynPoint(3, 4)
print(type(p))    # <class '__main__.DynPoint'>
print(type(DynPoint))   # <class 'type'>

Metaclass that enforces method naming conventions

class StrictMeta(type):
    def __new__(mcs, name, bases, namespace):
        for attr, val in namespace.items():
            if callable(val) and not attr.startswith('_'):
                if not attr.islower():
                    raise TypeError(
                        f"{name}.{attr}: public methods must be lowercase"
                    )
        return super().__new__(mcs, name, bases, namespace)

class Good(metaclass=StrictMeta):
    def compute(self): pass   # ok

try:
    class Bad(metaclass=StrictMeta):
        def ComputeValue(self): pass  # raises TypeError
except TypeError as e:
    print(e)

__init_subclass__ auto-register plugins

class Plugin:
    _registry: dict = {}

    def __init_subclass__(cls, name=None, **kwargs):
        super().__init_subclass__(**kwargs)
        key = name or cls.__name__.lower()
        Plugin._registry[key] = cls

class CSVPlugin(Plugin, name="csv"):
    pass

class JSONPlugin(Plugin, name="json"):
    pass

print(Plugin._registry)
# {'csv': <class 'CSVPlugin'>, 'json': <class 'JSONPlugin'>}

Common Mistakes

  • Confusing metaclass `__new__` with class `__new__` the metaclass `__new__` creates the *class*, not instances of it
  • Forgetting to call `super().__new__(...)` in the metaclass this skips the default class construction
  • Using a metaclass when `__init_subclass__` is sufficient metaclasses add complexity; prefer the simpler hook

Note

Ask yourself: "Do I need to control the creation of the class itself?" If yes, use a metaclass. If you just want to react when a subclass is defined, use `__init_subclass__`. If you want to modify instances, use regular `__init__` or decorators.

Exercises

Write Python code to solve each exercise. Run it in your browser and check your output.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What is the metaclass of a regular Python class?