__slots__ for Memory Optimization

RoadmapsPython

Overview

By default, Python objects store their instance attributes in a dynamic dictionary (`__dict__`). The `__slots__` attribute allows you to explicitly declare which attributes an instance can have. When you define `__slots__`, Python suppresses the creation of `__dict__` and allocates a fixed amount of space for the specified attributes. Think of `__dict__` as a flexible, expanding cargo container that takes up a lot of space, whereas `__slots__` is like a custom-molded foam insert that perfectly and rigidly fits only the tools you need. Python enforces a strict layout constraint when combining multiple slotted classes. You cannot inherit from multiple classes that define non-empty `__slots__`: class BaseA: __slots__ = ('a',) class BaseB: __slots__ = ('b',) class Child(BaseA, BaseB): # TypeError: multiple bases have instance lay-out conflict pass This limitation exists because Python must calculate a single, fixed memory layout for the instance structure.

Using `__slots__` drastically reduces the memory footprint of objects, which is critical when creating millions of instances. It also provides faster attribute access.

Where used: Pydantic, SQLAlchemy, Discord.py

Why learn this

Code walkthrough

class Point:
    __slots__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
print(p.x)

Focus: Notice how explicitly defining `__slots__` prevents the creation of a `__dict__` dictionary, making the `Point` objects more memory-efficient.

Common mistakes

Glossary

memory footprint
The total amount of computer memory or RAM that a program or object uses while running. For example, a class using `__slots__` uses less memory per instance. Example: `__slots__ = ('x', 'y')`.
rigidly
In a strict, inflexible way that cannot be easily changed or bent. A slotted object holds its attributes rigidly, raising an `AttributeError` for undeclared attributes. Example: `obj.new_attr = 1`.

Recall questions

Understanding checks

Why does a class with `__slots__` raise an `AttributeError` when you try to assign a new attribute not defined in the slots?

Because the class no longer has a dynamic `__dict__` to store arbitrary attributes.

When `__slots__` is defined, Python suppresses the creation of the `__dict__` and only allocates fixed space for the declared attributes, preventing any new attributes from being added dynamically.

Identify the bug in this inheritance setup that prevents it from saving memory.

`Point3D` does not define `__slots__`.

If a subclass doesn't define `__slots__`, Python will create a `__dict__` for it, defeating the memory optimization. `Point3D` should define `__slots__ = ('z',)`.

Identify why this class definition fails to compile.

A class cannot inherit from multiple base classes that define non-empty `__slots__`.

Python raises a `TypeError` because it cannot resolve the layout conflict between multiple fixed-memory bases. Only one parent can have non-empty `__slots__`.

Identify why this class definition fails to compile.

A class cannot inherit from multiple base classes that define non-empty `__slots__`.

Python raises a `TypeError` because it cannot resolve the layout conflict between multiple fixed-memory bases. Only one parent can have non-empty `__slots__`.

Practice tasks

Define a slotted class

The `Point` class uses a standard dictionary to store attributes. Modify the class to use `__slots__` for the `x` and `y` attributes to optimize memory.

Challenge

Fix the slotted inheritance

The `BaseEvent` class defines `__slots__` to save memory. However, `ClickEvent`, which inherits from `BaseEvent` and adds a `button` attribute, is consuming too much memory because instances are still being created with a `__dict__`. Fix `ClickEvent` so that it fully utilizes `__slots__` and saves memory.

Continue learning

Previous: Everything is an object in Python

Previous: Dictionaries: operations and use cases

Return to Python Roadmap