Skip to content

44. Classes and Metaclasses

type.__new__ and type.__init__, __init_subclass__, __set_name__, and metaclass resolution order.

A class is a runtime object that creates instances, stores attributes, participates in inheritance, and defines behavior through the Python object model. In CPython, a class is an object whose type is usually type.

A metaclass is the class of a class. It controls how class objects are created, initialized, represented, and called.

For normal classes:

class User:
    pass

print(type(User))

Output:

<class 'type'>

This means User is an object, and its type is type.

44.1 Classes Are Objects

A class definition creates a class object.

class User:
    name = "anonymous"

    def hello(self):
        return "hello"

After execution, User is a normal name bound in the surrounding namespace.

print(User)
print(type(User))
print(User.__name__)
print(User.__dict__)

The class object stores attributes such as:

__name__
__qualname__
__module__
__dict__
__bases__
__mro__
methods
descriptors
class variables
annotations

A class is not just syntax. It is a runtime object produced by executing a class statement.

44.2 Class Definition Is Execution

A class body is executable code.

class Example:
    print("inside class body")
    x = 1 + 2

Output during definition:

inside class body

The class body runs immediately when CPython executes the class statement. It is not delayed until an instance is created.

This matters because any top-level code inside the class body runs at class creation time:

class Bad:
    data = load_large_file()

That work happens when the class is defined.

44.3 The Class Creation Pipeline

A class definition:

class User(Base):
    x = 1

    def hello(self):
        return "hello"

is conceptually similar to:

namespace = {}
namespace["x"] = 1
namespace["hello"] = function_object
User = type("User", (Base,), namespace)

The real process has more steps:

1. Evaluate base classes.
2. Determine the metaclass.
3. Ask the metaclass for a class namespace.
4. Execute the class body in that namespace.
5. Create the class object.
6. Call descriptor __set_name__ methods.
7. Call subclass initialization hooks.
8. Bind the class object to its name.

This pipeline explains how metaclasses, descriptors, decorators, and inheritance interact.

44.4 Evaluating Base Classes

In:

class User(Model):
    pass

CPython first evaluates Model.

Base classes are expressions:

class User(get_base_class()):
    pass

The function call happens before the class object is created.

Multiple bases are evaluated left to right:

class C(A(), B()):
    pass

The resulting objects must be valid base classes or be transformable through __mro_entries__.

44.5 __mro_entries__

The hook __mro_entries__ allows non-class base objects to replace themselves during class creation.

This is used by some typing and generic machinery.

Example shape:

class BaseAlias:
    def __mro_entries__(self, bases):
        return (RealBase,)

class C(BaseAlias()):
    pass

Conceptually, CPython turns:

class C(BaseAlias()):
    pass

into:

class C(RealBase):
    pass

for inheritance purposes.

Most application code never implements __mro_entries__, but it is part of class creation.

44.6 Determining the Metaclass

The metaclass can be specified explicitly:

class User(metaclass=Meta):
    pass

If no metaclass is specified, CPython derives it from the base classes.

For a normal class:

class User:
    pass

the metaclass is:

type

For a subclass:

class Child(Base):
    pass

the metaclass is usually type(Base) or a compatible derived metaclass.

The selected metaclass must be compatible with the metaclasses of all base classes. Otherwise CPython raises a metaclass conflict.

44.7 Metaclass Conflict

A metaclass conflict happens when base classes require incompatible metaclasses.

Example:

class MetaA(type):
    pass

class MetaB(type):
    pass

class A(metaclass=MetaA):
    pass

class B(metaclass=MetaB):
    pass

class C(A, B):
    pass

This raises an error because CPython cannot choose a single metaclass that is compatible with both MetaA and MetaB.

The usual fix is to define a combined metaclass:

class MetaC(MetaA, MetaB):
    pass

class C(A, B, metaclass=MetaC):
    pass

Metaclass conflicts are common when combining frameworks that use metaclasses.

44.8 Preparing the Class Namespace

Before executing the class body, CPython asks the metaclass for a namespace.

It does this by calling __prepare__ if present.

class Meta(type):
    @classmethod
    def __prepare__(mcls, name, bases, **kwargs):
        return {}

class User(metaclass=Meta):
    x = 1

The returned object is used as the local namespace for the class body.

Historically, this enabled ordered class namespaces. Modern dictionaries preserve insertion order, but __prepare__ still supports custom namespace behavior.

Example use cases:

tracking declaration order
rejecting duplicate names
collecting field definitions
custom class DSLs
framework model declarations

44.9 Class Body Namespace

The class body executes with its own local namespace.

x = "global"

class Example:
    x = "class local"
    y = x

print(Example.x)
print(Example.y)

Output:

class local
class local

Assignments in the class body write into the class namespace, not into an instance.

Function bodies inside the class do not automatically capture class-local names:

class Example:
    x = 10

    def method(self):
        return x

This usually fails at runtime unless there is a global x, because method global lookup uses the module globals, not the class namespace.

Correct:

class Example:
    x = 10

    def method(self):
        return self.x

or:

class Example:
    x = 10

    def method(self):
        return type(self).x

44.10 Creating the Class Object

After executing the class body, CPython calls the metaclass.

For a normal class, this means calling type.

Conceptually:

User = type("User", bases, namespace)

The call to type creates a PyTypeObject internally.

The resulting class object stores:

class name
base classes
method resolution order
class dictionary
type flags
slot tables
weakref support
instance layout
descriptor information
subclass relationships

A user-defined class is therefore a type object.

44.11 type(name, bases, namespace)

You can create classes manually with type.

def hello(self):
    return "hello"

User = type("User", (), {"hello": hello})

u = User()
print(u.hello())

This is equivalent in spirit to:

class User:
    def hello(self):
        return "hello"

The class statement is syntax for a structured class creation protocol.

44.12 Metaclass __new__

A metaclass can customize class creation by overriding __new__.

class Meta(type):
    def __new__(mcls, name, bases, namespace, **kwargs):
        print("creating", name)
        return super().__new__(mcls, name, bases, namespace)

class User(metaclass=Meta):
    pass

Output:

creating User

__new__ receives the class name, base classes, and namespace before the class object exists.

Use __new__ when you need to change the class before creation:

modify namespace
validate definitions
inject methods
collect metadata
change base classes
control class object allocation

44.13 Metaclass __init__

A metaclass can customize class initialization by overriding __init__.

class Meta(type):
    def __init__(cls, name, bases, namespace, **kwargs):
        print("initializing", name)
        super().__init__(name, bases, namespace)

class User(metaclass=Meta):
    pass

__init__ receives the already created class object as cls.

Use metaclass __init__ when you need to register or inspect the class after creation:

register subclasses
validate final class
attach metadata
update external registries

44.14 Metaclass __call__

Calling a class is controlled by its metaclass.

For a normal class:

u = User("Ada")

is handled by:

type(User).__call__(User, "Ada")

For normal metaclasses, type.__call__ performs:

1. call User.__new__(User, ...)
2. if result is an instance of User, call User.__init__(instance, ...)
3. return instance

A metaclass can override __call__:

class SingletonMeta(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance

class Config(metaclass=SingletonMeta):
    pass

Now every Config() call returns the same object.

Use this sparingly. Metaclass __call__ changes instance creation globally for the class.

44.15 Instance Creation

For a normal class:

class User:
    def __new__(cls, name):
        print("__new__")
        return super().__new__(cls)

    def __init__(self, name):
        print("__init__")
        self.name = name

u = User("Ada")

Output:

__new__
__init__

__new__ creates the object.

__init__ initializes the object.

__new__ is a static-like constructor. It receives the class and returns an object.

__init__ receives the created instance and should return None.

44.16 Class Dictionaries

A class exposes its namespace through __dict__.

class User:
    kind = "human"

    def hello(self):
        return "hello"

print(User.__dict__)

User.__dict__ is usually a read-only mapping proxy.

print(type(User.__dict__))

You cannot assign directly into the mapping proxy:

User.__dict__["x"] = 1

But you can assign attributes on the class:

User.x = 1

This updates the underlying class dictionary through type machinery.

44.17 Class Variables

A class variable is stored on the class object.

class Counter:
    count = 0

Access through the class:

print(Counter.count)

Access through an instance:

c = Counter()
print(c.count)

If the instance does not have count, lookup finds it on the class.

Assignment through the instance creates or updates an instance attribute:

c.count = 10

print(c.__dict__)
print(Counter.count)

Output:

{'count': 10}
0

This is a common source of bugs with mutable class variables.

44.18 Mutable Class Variable Pitfall

class Bag:
    items = []

    def add(self, item):
        self.items.append(item)

Usage:

a = Bag()
b = Bag()

a.add("x")
print(b.items)

Output:

['x']

Both instances share the same class-level list.

Correct design:

class Bag:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

Use class variables for shared constants or intentional shared state. Use instance variables for per-instance state.

44.19 Instance Dictionaries

Normal user-defined objects have an instance dictionary.

class User:
    pass

u = User()
u.name = "Ada"

print(u.__dict__)

Output:

{'name': 'Ada'}

Attribute assignment stores values in the instance dictionary unless a data descriptor intercepts the assignment.

This is why Python objects are flexible by default. New attributes can be added dynamically.

44.20 __slots__ and Instance Layout

A class can define __slots__ to use fixed attribute slots instead of a normal instance dictionary.

class Point:
    __slots__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y

Instances of Point store x and y in fixed slots.

p = Point(1, 2)

print(hasattr(p, "__dict__"))

Usually:

False

Slots create descriptors on the class:

print(Point.__dict__["x"])
print(Point.__dict__["y"])

These descriptors read and write fixed storage locations.

44.21 Inheritance

A class can inherit from one or more base classes.

class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "woof"

The subclass stores its base classes in __bases__.

print(Dog.__bases__)

The method resolution order is stored in __mro__.

print(Dog.__mro__)

Attribute lookup follows the MRO.

44.22 Method Resolution Order

For:

class A:
    def f(self):
        return "A"

class B(A):
    pass

class C(B):
    pass

C().f() finds f in A through the MRO.

print(C.__mro__)

Output shape:

(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

The MRO is computed when the class is created. CPython uses C3 linearization for new-style classes.

44.23 Multiple Inheritance

Python supports multiple inheritance.

class A:
    def f(self):
        return "A"

class B:
    def f(self):
        return "B"

class C(A, B):
    pass

print(C().f())
print(C.__mro__)

The leftmost base usually has priority, subject to the C3 MRO rules.

Output:

A
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

Multiple inheritance is powerful, but it requires cooperative design when classes share methods and initialization paths.

44.24 Cooperative super

super() follows the MRO.

class A:
    def f(self):
        return "A"

class B(A):
    def f(self):
        return "B" + super().f()

class C(A):
    def f(self):
        return "C" + super().f()

class D(B, C):
    def f(self):
        return "D" + super().f()

print(D().f())
print(D.__mro__)

Output:

DBCA

super() does not mean “call my parent.” It means “continue the MRO after the current class.”

This is essential in multiple inheritance.

44.25 Class Decorators

A class decorator receives the class object after it is created.

def register(cls):
    registry[cls.__name__] = cls
    return cls

registry = {}

@register
class User:
    pass

This is roughly:

class User:
    pass

User = register(User)

Class decorators are often simpler than metaclasses. Use a metaclass only when class creation itself must be controlled across a family of classes.

44.26 __init_subclass__

A base class can define __init_subclass__ to run code when it is subclassed.

class Model:
    registry = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Model.registry.append(cls)

class User(Model):
    pass

class Post(Model):
    pass

print(Model.registry)

This is often simpler than a metaclass for subclass registration.

Use __init_subclass__ for:

subclass registration
subclass validation
default subclass configuration
lightweight framework hooks

44.27 __set_name__ During Class Creation

After creating a class, CPython calls __set_name__ on descriptors in the class namespace.

class Field:
    def __set_name__(self, owner, name):
        print(owner, name)

class User:
    id = Field()
    name = Field()

Output shape:

<class '__main__.User'> id
<class '__main__.User'> name

This lets descriptors discover the class and attribute name they are assigned to.

The ordering is:

class body executes
class object is created
descriptor __set_name__ hooks run
__init_subclass__ hooks run on bases
class decorators run
class name is bound

44.28 Metaclasses vs Class Decorators vs __init_subclass__

MechanismRunsBest for
MetaclassDuring class creationDeep control over class object creation
Class decoratorAfter class creationOne-off transformation or registration
__init_subclass__When subclass is createdBase-class-driven subclass hooks
Descriptor __set_name__During class finalizationField name discovery

Prefer the simplest mechanism that solves the problem.

For most code:

class decorator > __init_subclass__ > metaclass

A metaclass is justified when you need to customize namespace preparation, class allocation, metaclass-level methods, class calling, or enforce rules across a class hierarchy.

44.29 Metaclass Example: Enforcing Required Attributes

class RequireTableName(type):
    def __new__(mcls, name, bases, namespace):
        cls = super().__new__(mcls, name, bases, namespace)

        if bases and not hasattr(cls, "table_name"):
            raise TypeError(f"{name} must define table_name")

        return cls

class Model(metaclass=RequireTableName):
    pass

class User(Model):
    table_name = "users"

This metaclass validates subclasses.

This can also be implemented with __init_subclass__, which is often simpler:

class Model:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        if not hasattr(cls, "table_name"):
            raise TypeError(f"{cls.__name__} must define table_name")

Use the base-class hook unless the metaclass gives a concrete advantage.

44.30 Metaclass Example: Registry

class RegistryMeta(type):
    registry = {}

    def __init__(cls, name, bases, namespace):
        super().__init__(name, bases, namespace)
        if name != "Base":
            RegistryMeta.registry[name] = cls

class Base(metaclass=RegistryMeta):
    pass

class User(Base):
    pass

class Post(Base):
    pass

print(RegistryMeta.registry)

This records subclasses as they are created.

Again, __init_subclass__ may be enough:

class Base:
    registry = {}

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Base.registry[cls.__name__] = cls

Metaclasses should be used when they simplify the system, not when they merely feel powerful.

44.31 Metaclass Example: Custom Namespace

A metaclass can reject duplicate attribute names by returning a custom namespace from __prepare__.

class NoDuplicateDict(dict):
    def __setitem__(self, key, value):
        if key in self:
            raise TypeError(f"duplicate name: {key}")
        super().__setitem__(key, value)

class NoDuplicateMeta(type):
    @classmethod
    def __prepare__(mcls, name, bases):
        return NoDuplicateDict()

class Example(metaclass=NoDuplicateMeta):
    x = 1
    y = 2

If x were assigned twice, class creation would fail.

This is one case where a metaclass is appropriate because only the metaclass can customize the class-body namespace before execution.

44.32 Built-in Classes and Heap Types

CPython has both statically defined built-in types and dynamically allocated heap types.

Examples of built-in types:

int
str
list
dict
tuple
type
object

Many built-in types are defined in C.

User-defined classes are heap types created at runtime.

Both participate in the same object model:

print(type(list))
print(type(object))
print(type(type))

Output:

<class 'type'>
<class 'type'>
<class 'type'>

Even built-in classes are objects.

44.33 object and type

The relationship between object and type is central.

print(isinstance(object, type))
print(isinstance(type, object))
print(type(type))
print(type(object))

Important facts:

object is the base class of most Python objects
type is the default metaclass of classes
type is an instance of itself
object is an instance of type
type inherits from object

This circular-looking structure is carefully bootstrapped inside CPython.

It allows classes to be objects while still having a root inheritance hierarchy.

44.34 CPython Type Objects

At the C level, a class object is represented by a type object, commonly PyTypeObject.

A type object contains:

object header
type name
basic instance size
item size for variable-sized objects
method table
slot functions
base classes
MRO
dictionary
flags
allocation functions
deallocation functions
attribute access functions
call behavior
numeric, sequence, and mapping operation tables

This is why classes control object behavior. The class object contains the function pointers and metadata used by the runtime.

44.35 Type Slots

Python special methods often correspond to C-level slots.

Examples:

Python methodRuntime operation
__len__length operation
__getitem__indexing
__setitem__item assignment
__iter__iteration
__next__iterator next
__call__call
__add__numeric addition
__getattribute__attribute lookup
__new__allocation
__init__initialization

When a class is created, CPython builds slot tables from special methods.

This lets bytecode and C APIs call operations efficiently without performing a normal Python attribute lookup every time.

44.36 Special Method Lookup

Special method lookup often bypasses instance dictionaries.

Example:

class Example:
    pass

e = Example()
e.__len__ = lambda: 10

len(e)

This raises TypeError, because len(e) looks for __len__ on the type, not as an arbitrary instance attribute.

Correct:

class Example:
    def __len__(self):
        return 10

e = Example()
print(len(e))

Special methods belong on the class so CPython can populate and use type slots.

44.37 Attribute Lookup for Classes

For instance access:

obj.attr

CPython searches the instance and its class hierarchy.

For class access:

Class.attr

CPython searches the class object and its metaclass.

Example:

class Meta(type):
    label = "meta"

class User(metaclass=Meta):
    label = "class"

print(User.label)

Output:

class

If label is absent from User, lookup may find it on Meta.

Metaclasses define behavior and attributes of class objects.

44.38 Metaclass Methods

A metaclass method is a method on the class object.

class Meta(type):
    def describe(cls):
        return cls.__name__

class User(metaclass=Meta):
    pass

print(User.describe())

Here, describe is found on Meta and bound to User.

This is analogous to how instance methods are found on User and bound to user_instance.

instance method:
    User.method -> bound to instance

metaclass method:
    Meta.method -> bound to class object

44.39 Classes and Descriptors

Class dictionaries store descriptors.

class User:
    @property
    def name(self):
        return "Ada"

print(User.__dict__["name"])

When an instance accesses name, descriptor logic runs.

u = User()
print(u.name)

Methods are descriptors too:

class User:
    def hello(self):
        return "hello"

u = User()
print(u.hello)

The function stored in User.__dict__ binds to u through its descriptor __get__.

44.40 Classes and Garbage Collection

Class objects can participate in reference cycles.

Examples:

class object references methods
methods reference globals
functions reference code objects
closures may reference class-related state
instances reference class
class may reference descriptors
descriptors may reference owner class

CPython’s cyclic garbage collector can collect unreachable classes and related objects if they are not kept alive by other references.

Most ordinary classes live until process exit because modules keep references to them.

class User:
    pass

The module dictionary holds User.

44.41 Classes and Modules

A class records the module where it was defined.

class User:
    pass

print(User.__module__)

Usually:

__main__

or the module name.

This affects representation, pickling, documentation, and introspection.

A class does not physically belong to a module. The module dictionary merely holds a reference to the class object.

OtherName = User

Now the same class object has another name.

44.42 Class Identity

Class identity is object identity.

class User:
    pass

A = User
B = User

print(A is B)

Output:

True

If a module is imported twice under different names, class objects may be duplicated.

package.models.User
models.User

These may be different class objects even if they came from the same file.

That breaks isinstance, registry lookup, serialization, and singleton assumptions.

44.43 Class Annotations

Class annotations are stored in __annotations__.

class User:
    id: int
    name: str = "anonymous"

print(User.__annotations__)

Output:

{'id': <class 'int'>, 'name': <class 'str'>}

Annotations do not automatically create instance fields.

u = User()
print(hasattr(u, "id"))

Usually:

False

Frameworks such as dataclasses, attrs, Pydantic, and ORMs inspect annotations to generate behavior.

44.44 Dataclasses as Class Transformation

dataclasses.dataclass is a class decorator.

from dataclasses import dataclass

@dataclass
class User:
    id: int
    name: str

It receives the class object, inspects annotations, and adds methods such as:

__init__
__repr__
__eq__

This shows that major class behavior can be added after class creation without a metaclass.

44.45 Abstract Base Classes

The abc module uses metaclass machinery.

from abc import ABC, abstractmethod

class Store(ABC):
    @abstractmethod
    def get(self, key):
        pass

ABC uses ABCMeta, a metaclass that tracks abstract methods and prevents instantiation until they are implemented.

class BadStore(Store):
    pass

BadStore()

This raises TypeError.

Abstract base classes are a practical example of metaclasses enforcing class contracts.

44.46 Classes and isinstance

isinstance(obj, cls) usually checks whether type(obj) is cls or a subclass of cls.

class Animal:
    pass

class Dog(Animal):
    pass

d = Dog()

print(isinstance(d, Dog))
print(isinstance(d, Animal))

Metaclasses can customize this through __instancecheck__.

ABC machinery uses this for virtual subclass behavior.

44.47 Classes and issubclass

issubclass(A, B) checks whether class A is a subclass of class B.

class A:
    pass

class B(A):
    pass

print(issubclass(B, A))

Metaclasses can customize this through __subclasscheck__.

This is another place where class behavior is mediated by metaclass logic.

44.48 Dynamic Class Creation

Dynamic class creation is useful in frameworks and code generation.

def make_model(name, fields):
    namespace = {"__annotations__": fields}
    return type(name, (), namespace)

User = make_model("User", {"id": int, "name": str})

print(User)
print(User.__annotations__)

Dynamic classes should still follow ordinary class rules:

valid name
clear module
stable identity
predictable bases
explicit public API

Set __module__ when needed:

namespace = {
    "__module__": __name__,
    "__annotations__": fields,
}

This improves introspection and serialization.

44.49 When to Use a Metaclass

Use a metaclass when you need one of these:

custom class namespace through __prepare__
control over class allocation through __new__
metaclass-level methods or properties
custom class call behavior
deep integration across a class hierarchy
framework-level class validation
special instance or subclass checks

Avoid metaclasses for simple registration, validation, or method generation when class decorators or __init_subclass__ are enough.

Metaclasses are global to a class hierarchy. They compose poorly when unrelated libraries define different metaclasses.

44.50 Key Points

A class is a runtime object.

Most classes are instances of type.

A metaclass is the type of a class.

Class definitions execute a body, collect a namespace, and call a metaclass to create the class object.

Instances are created by calling a class, which is handled by the metaclass __call__.

Class dictionaries store methods, descriptors, annotations, and class variables.

Inheritance uses the method resolution order.

Special methods are installed into type slots and are usually looked up on the class, not the instance.

Descriptors, __set_name__, __init_subclass__, class decorators, and metaclasses all participate in class construction.

Use metaclasses only when simpler class mechanisms cannot express the required behavior.