Site Tools


python-metaclasses

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__:

  • __new__(mcs, name, bases, dct): create the class object itself
  • __init__(cls, name, bases, dct): initialize the created class
  • Typically override __new__ to modify the class before it's created

Enforcing conventions:

  • Require all methods to have docstrings
  • Enforce naming conventions (e.g., private methods start with _)
  • Auto-generate __repr__ or __str__

Auto-registration:

  • Maintain registry of all subclasses
  • Useful for plugin systems, handlers, strategies

Modifying class attributes:

  • Auto-wrap methods (add timing, caching, logging)
  • Generate properties from class attributes
  • Add descriptor methods automatically

Inheriting metaclasses:

  • If Base has metaclass M1 and Derived(Base) has metaclass M2, Python requires M2 to be a subclass of M1
  • Resolve conflicts with intermediate metaclass combining them

When to avoid:

  • Descriptors or decorators are usually simpler
  • Metaclasses are hard to debug and understand
  • Over 99% of code doesn't need metaclasses
python-metaclasses.md · Last modified: by 127.0.0.1