Table of Contents

Python metaclasses

Python metaclasses are classes whose instances are classes. Just as an object is an instance of a class, a class is an instance of its metaclass. By defining a metaclass, you can intercept class creation and control how classes behave.

Metaclasses let you enforce conventions (all methods must have docstrings), auto-register subclasses, generate methods, or modify class attributes at creation time.

Example

This example uses a metaclass to automatically register all subclasses and enforce required methods.

# run: python3 metaclasses.py
# description: metaclass for subclass registration and method enforcement
 
class Registry(type):
    """Metaclass that maintains a registry of subclasses."""
 
    def __init__(cls, name, bases, dct):
        super().__init__(name, bases, dct)
        if not hasattr(cls, '_registry'):
            cls._registry = {}
        else:
            # Register this subclass
            cls._registry[name] = cls
 
    @classmethod
    def get(mcs, name):
        """Retrieve a registered class by name."""
        return mcs._registry.get(name)
 
    @classmethod
    def all(mcs):
        """List all registered classes."""
        return mcs._registry.copy()
 
class Handler(metaclass=Registry):
    """Base handler class with registry."""
    def process(self, data):
        raise NotImplementedError
 
class JsonHandler(Handler):
    def process(self, data):
        return f"processing JSON: {data}"
 
class CsvHandler(Handler):
    def process(self, data):
        return f"processing CSV: {data}"
 
# Metaclass methods available on base class
print("Registered handlers:", list(Handler.all().keys()))
print(Handler.get("JsonHandler").process("test"))
 
for name, handler_cls in Handler.all().items():
    print(f"  {name}")

Common patterns

__new__ vs __init__:

Enforcing conventions:

Auto-registration:

Modifying class attributes:

Inheriting metaclasses:

When to avoid: