__slots__
Declare exactly which attributes a class can have to reduce memory usage and speed up attribute access for large object counts.
"__slots__ trades flexibility for speed and memory. When you have thousands of objects of the same class, the difference is real and measurable."
— ShurAIHow Python Normally Stores Attributes
By default, every Python object carries a __dict__ — a dictionary that stores all its attributes. This is flexible (you can add any attribute anytime) but uses memory and is slower to look up:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.__dict__) # {'x': 1, 'y': 2} — dict overhead for every instance
# You can add any attribute at runtime (flexible but unpredictable)
p.color = "red" # works — even if you never intended this
__slots__ — Declare Allowed Attributes
Define __slots__ to tell Python exactly which attributes an instance can have. Python replaces the __dict__ with a compact fixed-size structure for each slot:
class PointSlotted:
__slots__ = ["x", "y"] # only these attributes allowed
def __init__(self, x, y):
self.x = x
self.y = y
p = PointSlotted(1, 2)
print(p.x) # 1 — works normally
# p.__dict__ → AttributeError: no __dict__
# p.color = "red" → AttributeError: 'color' not in __slots__
The Memory and Speed Benefit
__dict__.~56 bytes per instance baseline
+ dict overhead per object.
~40% less memory per instance.
Also faster attribute access.
import sys
class Normal:
def __init__(self, x, y):
self.x, self.y = x, y
class Slotted:
__slots__ = ["x", "y"]
def __init__(self, x, y):
self.x, self.y = x, y
n = Normal(1, 2)
s = Slotted(1, 2)
print(f"Normal: {sys.getsizeof(n)} bytes") # Normal: 48 bytes
print(f"Slotted: {sys.getsizeof(s)} bytes") # Slotted: 32 bytes
When to Use __slots__
Class attributes are fixed and well-known
Performance-critical inner loops
You need pickling or
__dict__-based toolsOnly a handful of instances — no measurable benefit
Real Example — Particle Simulation
class Particle:
"""Compact particle for a physics simulation.
Millions of these may exist at once."""
__slots__ = ["x", "y", "vx", "vy", "mass"]
def __init__(self, x, y, vx=0.0, vy=0.0, mass=1.0):
self.x, self.y = x, y
self.vx, self.vy = vx, vy
self.mass = mass
def move(self, dt):
self.x += self.vx * dt
self.y += self.vy * dt
# Create 1,000,000 particles efficiently
particles = [Particle(i * 0.01, i * 0.01) for i in range(1_000_000)]
for p in particles:
p.move(0.016)
"__slots__ is a micro-optimisation you should reach for deliberately, not by default. Measure first. If memory or speed is genuinely a bottleneck and your class is simple, then slots are the right tool."
— ShurAI🧠 Quiz — Q1
What does Python use by default to store instance attributes, and why is it a cost?
🧠 Quiz — Q2
What does defining __slots__ = ["x", "y"] in a class do?
🧠 Quiz — Q3
What happens if you try to add a new attribute to a slotted instance that is not in __slots__?
🧠 Quiz — Q4
When is __slots__ most beneficial?