Alex Lin Wang 王帅

__slots__

August 28, 2025 • 5 min read
Optimize memory usage and improve performance with Python's __slots__. Learn how to replace the default __dict__ with a more efficient storage mechanism for class instances.

Dictionaries are the favorite workhouse of the Pythonic style. Specifically in the cases of classes, instance attributes are stored in a __dict__ dunder, which is flexible, but uses a lot of overhead as each instance has its own dictionary. Creating millions of class instances for small objects can thus result in memory/performance issues.

Imagine, if you wanted to have a class that stored a datapoint as such:

class Point3D:
    def __init__(self, x: float, y: float, z: float) -> None:
        self.x = x
        self.y = y
        self.z = z

point1 = Point3D(1, 2, 3)
point1.__dict__     # This would be {\"x\": 1, \"y\": 2, \"z\": 3}

You may think it would be better to accomplish this with the @dataclass decorator, but the underlying implementation of a @dataclass is still a __dict__.

__slots__ is a memory-efficient alternative to __dict__. When you define __slots__, you declare what attributes an instance has, resulting in a much more efficient storage mechanism. The underlying implementation is a compact C array indexed by slot position.

class SlottedPoint3D:
    __slots__ = ("x", "y", "z") 
    
    def __init__(self, x: float, y: float, z: float) -> None:
        self.x = x
        self.y = y
        self.z = z

Python now allocates a fixed amount of memory with slot descriptor objects with pre-defined methods like __get__ and __set__ which index into the array. This direct memory lookup is faster than a dictionary lookup. You can even use dataclasses with direct slots support (Python 3.10+).

from dataclasses import dataclass

@dataclass(slots=True)
class SlottedPoint3D: 
    x: int
    y: int
    z: int

Here is a quick comparison after generating it. Check out the link here.

Memory per object (bytes)

Type dict normal slots
bytes 424 584 152

Total creation time (seconds)

N dict normal slots
10 0.000027 0.000011 0.000009
100 0.000044 0.000052 0.000041
1,000 0.000322 0.000501 0.000397
10,000 0.003644 0.004629 0.004458
100,000 0.047655 0.053937 0.047593
1,000,000 0.520809 0.531388 0.399850

Per-object creation time (nanoseconds)

N dict normal slots
10 2672.10 1126.80 858.20
100 444.87 520.00 410.34
1,000 321.81 500.76 396.53
10,000 364.41 462.94 445.79
100,000 476.55 539.37 475.93
1,000,000 520.81 531.39 399.85

However, there is a tradeoff, here are some differences:

  • You cannot add more attributes after predefining slots during instantiation.
  • You cannot dynamically add attributes.
  • You need to redeclare __slots__ in subclasses.
  • You cannot set class attributes for defaults in __slots__ (but you can add class-level constants).

Questions or feedback? Feel free to reach out!