What metaclasses are in Python

A metaclass is the class of a class. That sentence is correct and completely useless on its own, so this article builds up to it, shows when each hook actually fires, and then argues that you probably want something simpler.

Classes are objects

This is the piece you need first. In Python a class is not a compile-time declaration — it is an object, created at runtime, that you can pass around:

type(42)          : int
type(Plain)       : type   <- the class itself has a type
type(type)        : type   <- type is its own type
isinstance(Plain, object) : True

42 is an instance of int. Plain is an instance of type. And type is an instance of itself, which is where the recursion stops.

type() with three arguments builds a class

You have used type() with one argument. With three it creates a class:

Dynamic = type("Dynamic", (), {"greet": lambda self: "hello", "version": 1})
type('Dynamic', (), {...}) -> <class '__main__.Dynamic'>
d.greet()   : hello
d.version   : 1

Name, base classes, namespace. This is not a trick — it is what the class statement does. Python collects the body into a dictionary and calls type.

A metaclass replaces that call

If type is what normally builds your class, a metaclass is what you put in its place:

class Meta(type):
    def __new__(mcls, name, bases, namespace, **kwargs):
        namespace["added_by_meta"] = True
        return super().__new__(mcls, name, bases, namespace)

class Made(metaclass=Meta):
    x = 1
Meta.__new__ running for 'Made'
  bases     : ()
  namespace : ['method', 'x']
type(Made)            : Meta
Made.added_by_meta    : True   <- the metaclass put it there

The metaclass saw the class being built, modified the namespace, and the attribute exists on the finished class.

When the hooks run

This is the part worth pinning down, because getting it wrong is the source of most metaclass confusion:

1. __prepare__ (returns the namespace mapping)
2. __new__ (creates the class object)
3. __init__ (class object already exists)
now instantiating:
4. __call__ (only when an INSTANCE is made)

The first three run once, when the class is defined. Not per instance. Creating two instances of Made produces no further output at all:

creating two instances now -- note that Meta.__new__ does NOT run again:
(nothing printed)

__call__ is the odd one out — it runs when somebody writes Made(), and it is how you control instantiation:

class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]
Config() is Config() : True

Metaclasses are inherited

type(Child) : Meta   <- inherited from Made

Subclasses get the metaclass too, and __new__ runs again for each of them — with bases now non-empty. That difference is how the registry pattern below avoids registering its own base class.

What they are actually used for

The honest answer is: a registry, an ORM, or a framework that needs to know about every subclass somebody writes.

class PluginMeta(type):
    registry = {}
    def __init__(cls, name, bases, namespace):
        super().__init__(name, bases, namespace)
        if bases:                       # skip the base class itself
            PluginMeta.registry[name.lower()] = cls
registry after defining two subclasses : ['csvexporter', 'jsonexporter']
-> no explicit registration call anywhere

Defining a subclass is enough. Nobody has to remember a decorator or a registration call, which is exactly why Django models and SQLAlchemy work the way they do.

But you probably want init_subclass

Since Python 3.6 there is a hook that does the same job without a metaclass, from PEP 487:

class Base:
    registry = {}
    def __init_subclass__(cls, /, label=None, **kwargs):
        super().__init_subclass__(**kwargs)
        Base.registry[label or cls.__name__.lower()] = cls

class Alpha(Base, label="a"):
    pass
registry : ['a', 'beta']

Same result, ordinary class, and it even takes keyword arguments from the class definition. There is also __set_name__ for the descriptor case.

Between them these two cover most of what metaclasses were reached for, and they avoid the following problem.

The reason to avoid them in library code

Every class has exactly one metaclass. If you inherit from two classes with different ones, Python cannot proceed:

class UsesA(metaclass=MetaA): pass
class UsesB(metaclass=MetaB): pass
class Both(UsesA, UsesB): pass
TypeError: metaclass conflict: the metaclass of a derived class must be a
(non-strict) subclass of the metaclasses of all its bases

The only fix is a third metaclass inheriting from both — which you can only write if you control both libraries. If you ship a metaclass in a public package, you have made your users’ inheritance decisions for them.

You already use them

Three you have certainly met:

type(abc.ABC)          : ABCMeta
type(an Enum subclass) : EnumType
type(int)              : type

abc uses ABCMeta to make instantiating an abstract class an error, and enum uses EnumType for the member lookup and the iteration order. Both are good examples of the thing being worth it: framework-level behaviour that would otherwise be manual on every subclass.

About Netcup (advertisement)

The German host Netcup offers, among other things, affordable and powerful web hosting packages, KVM-based root servers and dedicated servers. With our voucher codes you can save even more (6€ off your first order, 30% off all KVM-based root servers, ...).