Metaclasses & Class Customization

15 questions found

What is a metaclass in Python, and what is the default metaclass for all classes?

Beginner
A metaclass is 'the class of a class' -- it defines how classes themselves are constructed, just as a class defines how instances are constructed. The default metaclass for all classes in Python is `type`; when you write `class Foo: pass`, Python actually calls `type('Foo', (), {})` behind the scenes to create the class object.
class Foo:
    pass

print(type(Foo))       # <class 'type'>
print(type(Foo()))     # <class '__main__.Foo'>
print(isinstance(Foo, type))  # True
Real-world example Understanding that classes are themselves objects (instances of type) explains why you can dynamically create classes at runtime using type() directly, without a class statement.

Common follow-ups: How is type() used both as a function and as the base metaclass?;What's the class hierarchy of type itself?

Multiple Inheritance & MRO;Descriptors & Properties

How do you create a class dynamically using type() with three arguments instead of a class statement?

Intermediate
type(name, bases, namespace) creates a new class object: name is the class's __name__ string, bases is a tuple of parent classes, and namespace is a dict of attributes and methods. This is exactly what the `class` keyword does internally, and calling type() directly lets you generate classes programmatically at runtime.
def greet(self):
    return f'Hello, {self.name}'

Person = type('Person', (object,), {
    '__init__': lambda self, name: setattr(self, 'name', name),
    'greet': greet,
})

p = Person('Alice')
print(p.greet())  # Hello, Alice
Real-world example An ORM framework dynamically generates model classes at import time using type(), building each class's attributes from a database schema definition rather than hand-writing every class.

Common follow-ups: When would dynamic class creation be preferable to a class statement?;How does this relate to class decorators as an alternative?

Multiple Inheritance & MRO;Decorators

How do you write a custom metaclass by subclassing type, and when would you do so?

Advanced
A custom metaclass subclasses `type` and overrides __new__ and/or __init__ to customize class creation itself -- for example, validating that subclasses implement required methods, auto-registering every subclass in a registry, or injecting attributes into every class using the metaclass. You use it via `class MyClass(metaclass=MyMeta):`.
class ValidatingMeta(type):
    def __new__(mcs, name, bases, namespace):
        if 'process' not in namespace and bases:
            raise TypeError(f'{name} must implement process()')
        return super().__new__(mcs, name, bases, namespace)

class Base(metaclass=ValidatingMeta):
    def process(self): pass

class Bad(Base):  # raises TypeError: missing process()
    pass
Real-world example A plugin framework uses a metaclass to automatically register every subclass of a Plugin base class into a global registry dict as soon as it's defined, enabling plugin discovery without explicit registration calls.

Common follow-ups: Why do most Python developers reach for __init_subclass__ instead of a full metaclass?;How do metaclasses interact with multiple inheritance?

Multiple Inheritance & MRO;Decorators

How does __init_subclass__ provide a simpler alternative to metaclasses for many customization needs?

Intermediate
__init_subclass__(cls, **kwargs) is a classmethod automatically called whenever a subclass is defined, letting you hook into subclass creation (validation, registration, attribute injection) without writing a full metaclass. It's simpler because you just define it in the base class, and Python 3.6+ handles the rest -- covering the majority of use cases that used to require a custom metaclass.
class Plugin:
    registry = []
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Plugin.registry.append(cls)

class MyPlugin(Plugin):
    pass

print(Plugin.registry)  # [<class 'MyPlugin'>]
Real-world example A web framework uses __init_subclass__ on a base View class to automatically register every route handler subclass, replacing what older versions implemented with a metaclass.

Common follow-ups: What can metaclasses do that __init_subclass__ cannot?;How do class keyword arguments work with __init_subclass__?

Multiple Inheritance & MRO;Decorators

How does __class_getitem__ enable generic-looking syntax like MyClass[int]?

Advanced
__class_getitem__(cls, item) is called when you subscript a class itself (not an instance), like `list[int]` or a custom `Container[str]`. It's primarily used to support type-hint syntax for generic classes without requiring inheritance from typing.Generic, returning a types.GenericAlias or custom object representing the parameterized type.
class Container:
    def __class_getitem__(cls, item):
        return f'{cls.__name__}[{item.__name__}]'

print(Container[int])  # 'Container[int]'
print(list[int])       # list[int] -- built-in generics support this too
Real-world example A typed collections library implements __class_getitem__ so users can write `Stack[int]` for type hints and IDE autocompletion without needing to inherit from typing.Generic explicitly.

Common follow-ups: How does this differ from typing.Generic's __class_getitem__?;Why was this added in PEP 560?

Data Types & Structures;Magic Methods & Operator Overloading

What role does the class namespace dict play during class creation, and how can __prepare__ customize it?

Intermediate
During class body execution, Python populates a namespace mapping (by default a plain dict) with all the names defined in the class body (methods, class variables), which is then passed to the metaclass's __new__/__init__. A metaclass's __prepare__(mcs, name, bases) classmethod can return a custom mapping (like an OrderedDict or one that tracks definition order or rejects duplicate names) to control how that namespace behaves during class body execution.
class OrderedMeta(type):
    @classmethod
    def __prepare__(mcs, name, bases):
        return {}  # could return a custom ordered/tracking mapping

    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)
        cls._field_order = list(namespace.keys())
        return cls
Real-world example An ORM metaclass uses __prepare__ with a custom mapping to preserve and later use the exact declaration order of model fields for generating a consistent database schema.

Common follow-ups: Why is __prepare__ less necessary since Python 3.7 (dicts are ordered)?;What other customizations can __prepare__ enable?

Data Types & Structures;Descriptors & Properties

How do abstract base classes (ABCs) use a metaclass to enforce that subclasses implement required methods?

Advanced
The abc module's ABCMeta metaclass tracks methods decorated with @abstractmethod, and when you attempt to instantiate a class (not subclass, but instantiate) that hasn't overridden all abstract methods, ABCMeta's __call__ raises TypeError before __init__ even runs. This enforces an interface contract at instantiation time rather than only failing later when a missing method is actually called.
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self): ...

class Circle(Shape):
    def __init__(self, r): self.r = r
    def area(self): return 3.14159 * self.r ** 2

try:
    Shape()  # TypeError: Can't instantiate abstract class
except TypeError as e:
    print(e)
Real-world example A plugin interface defines an abstract PaymentProcessor base class with abstractmethod charge() and refund(), guaranteeing every concrete payment integration implements both before it can even be instantiated.

Common follow-ups: How does ABCMeta interact with __init_subclass__?;What's the difference between ABC and Protocol for structural typing?

Multiple Inheritance & MRO;Exception Handling

What is the difference between a class decorator and a metaclass for customizing class behavior?

Intermediate
A class decorator (a function taking a class and returning a class, possibly modified) runs once after the class is fully created, making it simpler for straightforward modifications like adding methods or registering the class. A metaclass intervenes during the class creation process itself (before the class object fully exists), giving it more power -- like controlling the namespace, validating during creation, or affecting all subclasses automatically -- at the cost of more complexity.
def add_repr(cls):
    cls.__repr__ = lambda self: f'{cls.__name__}({self.__dict__})'
    return cls

@add_repr
class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

print(Point(1,2))  # Point({'x': 1, 'y': 2})
Real-world example A dataclass-like library offers both a simpler @auto_repr class decorator for basic use and a full metaclass-based system for advanced users needing automatic subclass registration.

Common follow-ups: When would you need a metaclass instead of a simpler class decorator?;Can class decorators and metaclasses be combined?

Decorators;Dataclasses & NamedTuples

Why can't you freely mix two classes with different, incompatible metaclasses in multiple inheritance?

Advanced
When a class inherits from multiple bases with different metaclasses, Python must determine a single metaclass for the new class that is a subclass of all the bases' metaclasses (found via metaclass conflict resolution); if no such common metaclass exists, Python raises `TypeError: metaclass conflict`. This is why combining ABCMeta-based classes with other custom metaclasses sometimes requires defining a new metaclass that inherits from both.
class MetaA(type): pass
class MetaB(type): pass
class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass

try:
    class C(A, B): pass  # TypeError: metaclass conflict
except TypeError as e:
    print(e)
Real-world example Combining a third-party ORM base class (using a custom metaclass) with an ABC-based interface sometimes forces you to define `class CombinedMeta(ORMMeta, ABCMeta): pass` and use it explicitly to resolve the conflict.

Common follow-ups: How do you resolve a metaclass conflict manually?;Why does Python require metaclass compatibility across bases?

Multiple Inheritance & MRO;Descriptors & Properties

How does __set_name__ let a descriptor discover the attribute name it's assigned to within a class?

Intermediate
__set_name__(self, owner, name) is automatically called on a descriptor instance by the class creation machinery (part of type.__new__), passing the owning class and the attribute name it was assigned to in the class body. This lets descriptors avoid requiring the name to be passed explicitly and manually kept in sync, reducing a common source of bugs.
class Field:
    def __set_name__(self, owner, name):
        self.name = f'_{name}'
    def __get__(self, obj, objtype=None):
        return getattr(obj, self.name, None)
    def __set__(self, obj, value):
        setattr(obj, self.name, value)

class Model:
    title = Field()  # __set_name__ called automatically with name='title'
Real-world example A validation library's Field descriptor uses __set_name__ to automatically derive its private storage attribute name from the public attribute name, eliminating a common copy-paste bug of mismatched names.

Common follow-ups: When was __set_name__ introduced and what problem did it solve (PEP 487)?;How does this interact with __init_subclass__?

Descriptors & Properties;Data Types & Structures

Showing 1–10 of 15