Metaclasses

Python 3.12 · ✓ verified by execution on 2026-07-30

When you define a class in Python, you’re creating a template for building objects. But what builds the class itself? The answer is a metaclass.

A metaclass is a “class of a class”. Just as an object is an instance of a class, a class is an instance of a metaclass. By default, all classes in Python are constructed using the built-in type() function, which acts as the default metaclass.

Here is a visualization distinguishing between class creation time and instance creation time:

type (Metaclass) MyClass (Class) m (Instance) creates creates
The Metaclass Object Model: type creates the class, the class creates the instance.
python · visualize
class MyMeta(type):
    def __new__(mcs, name, bases, namespace):
        print(f"1. Creating class {name}")
        return super().__new__(mcs, name, bases, namespace)

print("0. Before class definition")
class MyClass(metaclass=MyMeta):
    pass
print("2. After class definition")

m = MyClass()
print("3. Instance created")

Notice that the metaclass __new__ method runs while the class is being defined, completely independent of when (or if) you ever instantiate it!

The Default Metaclass

If you don’t specify a metaclass, Python uses type.

python
class MyClass:
    pass
print(type(MyClass))
Output
<class 'type'>

Customizing Class Creation with __new__

You can write your own metaclass by inheriting from type. The most common method to override is __new__, which takes four arguments:

  1. mcs: The metaclass itself.
  2. name: The name of the class being created.
  3. bases: A tuple of base classes.
  4. namespace: A dictionary containing the class attributes and methods.

Let’s modify a class namespace before the class even exists by converting all its custom attributes to uppercase!

python
class UppercaseMeta(type):
    def __new__(mcs, name, bases, namespace, **kwargs):
        uppercase_attr = {k.upper(): v for k, v in namespace.items() if not k.startswith('__')}
        return super().__new__(mcs, name, bases, uppercase_attr, **kwargs)

class MyClass(metaclass=UppercaseMeta):
    my_attr = 10

print(hasattr(MyClass, 'my_attr'))
print(hasattr(MyClass, 'MY_ATTR'))
Output
False
True

Class Factories and Registries

Metaclasses are sometimes referred to as class factories. A very common use case is building a registry of plugins. Whenever a new subclass is defined, the metaclass can automatically record it in a dictionary.

python
registry = {}
class PluginMeta(type):
    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)
        if name != 'BasePlugin':
            registry[name] = cls
        return cls

class BasePlugin(metaclass=PluginMeta):
    pass
class MyPlugin(BasePlugin):
    pass

print(list(registry.keys()))
Output
['MyPlugin']

Initialization with __init__

While __new__ creates the class object, you can also override __init__ on the metaclass to configure the class immediately after it has been created.

python
class InitMeta(type):
    def __init__(cls, name, bases, namespace):
        super().__init__(name, bases, namespace)
        cls.initialized_by_meta = True

class TestClass(metaclass=InitMeta):
    pass
print(TestClass.initialized_by_meta)
Output
True

Inheriting Metaclasses

The appropriate metaclass for a class is determined by looking at its explicit metaclass keyword argument or by checking its base classes. If a base class has a custom metaclass, the derived class will inherit it automatically.

python
class Meta(type):
    pass
class Base(metaclass=Meta):
    pass
class Derived(Base):
    pass
print(type(Derived))
Output
<class '__main__.Meta'>

Metaclass Conflicts

Because a class inherits metaclasses from its bases, multiple inheritance can cause problems. If you try to inherit from two classes that have different, unrelated metaclasses, Python won’t know which one to use to construct your new class!

python
class MetaA(type): pass
class MetaB(type): pass
class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass

try:
    class C(A, B): pass
except TypeError as e:
    print('TypeError')
Output
TypeError

To resolve this, you would have to manually create a new metaclass that inherits from both MetaA and MetaB, and specify it as the metaclass for C.

Metaclass vs __init_subclass__

While metaclasses are incredibly powerful, they are often overkill. Since Python 3.6, the __init_subclass__ classmethod provides a much simpler way to customize class creation (like building registries) without the complexity of metaclasses. The golden rule is: If __init_subclass__ can solve your problem, use it instead of a metaclass.

Check yourself

What is a metaclass, in one sentence?

Reveal answer

A class whose instances are themselves classes — type is the default metaclass: it creates class objects, exactly as a class creates instances.

When does a metaclass __new__ run?

Reveal answer

Once, when the class itself is defined — Metaclass hooks fire at class-creation time, which is why they suit registration and validation of the class body.

What problem do metaclasses typically solve?

Reveal answer

Registering or validating subclasses automatically as they are defined — Auto-registration (plugin systems) and enforcing that subclasses declare required attributes are the classic uses.

What is usually the better first choice than a metaclass?

Reveal answer

__init_subclass__ or a class decorator — __init_subclass__ covers most subclass-registration needs with far less machinery. Reach for a metaclass only when it cannot.

Challenges

Challenge 1 +100 XP

Create a metaclass `RequireDocstringMeta` that raises a `TypeError` if a class is defined without a docstring (`__doc__`). Apply it to `StrictClass`.

python
  • Test 1 — expects ""
Need a hint? (−25% XP)

Check the `namespace` dictionary for the `__doc__` key inside the metaclass's `__new__` method.

Show solution (0 XP)
class RequireDocstringMeta(type):
    def __new__(mcs, name, bases, namespace):
        if '__doc__' not in namespace or not namespace['__doc__']:
            raise TypeError('Class must have a docstring')
        return super().__new__(mcs, name, bases, namespace)

class StrictClass(metaclass=RequireDocstringMeta):
    """This class has a docstring."""
    pass

Challenge 2 +100 XP

Create a metaclass `SingletonMeta` that ensures only one instance of a class is ever created. Apply it to the `Database` class.

python
  • Test 1 — expects ""
Need a hint? (−25% XP)

Override the `__call__` method on the metaclass to intercept when the class is instantiated.

Show solution (0 XP)
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]

class Database(metaclass=SingletonMeta):
    pass