__slots__ Optimization — Core Concepts
What slots Actually Does
Every Python object normally carries a __dict__ — a dictionary that stores its attributes. Dictionaries are powerful but expensive: each one allocates a hash table, which consumes roughly 100-200 bytes even when nearly empty.
When you define __slots__ on a class, Python replaces __dict__ with fixed-size slots — essentially C-level struct fields. The object stores references in a compact array rather than a hash table.
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
This Point uses about 56 bytes per instance, compared to ~152 bytes without slots — a 63% reduction.
When the Savings Matter
The per-object savings seem small, but they compound:
| Objects | Without slots | With slots | Savings |
|---|---|---|---|
| 1,000 | 152 KB | 56 KB | 96 KB |
| 1,000,000 | 152 MB | 56 MB | 96 MB |
| 10,000,000 | 1.52 GB | 560 MB | ~1 GB |
Real-world examples where this matters:
- ORM model instances (Django, SQLAlchemy rows)
- Graph nodes in network analysis
- Coordinate points in geospatial data
- Tokens/nodes in parsers and AST walkers
The Rules
You can’t add new attributes
p = Point(1, 2)
p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
This is the fundamental trade-off. With __dict__, objects are bags of attributes. With __slots__, they’re fixed structures.
Inheritance gets tricky
If a parent class doesn’t define __slots__, the child still gets __dict__ through the parent. To get the full memory benefit, every class in the chain needs __slots__.
class Base:
__slots__ = ('a',)
class Child(Base):
__slots__ = ('b',) # Only 'b' here — 'a' comes from Base
If Child omits __slots__, it regains __dict__ and you lose the memory savings.
No default values in slots
__slots__ defines attribute names, not values. Default values go in __init__ or as class-level descriptors (which is an advanced pattern).
slots and dict can coexist
If you include '__dict__' in your slots tuple, the object gets both fixed slots and a dynamic dictionary:
class Hybrid:
__slots__ = ('x', 'y', '__dict__')
This gives you fast access for known attributes and flexibility for unknown ones. It’s occasionally useful but defeats much of the memory purpose.
Speed Benefits
Attribute access on slotted objects is slightly faster because Python doesn’t need to hash the attribute name and look it up in a dictionary. It uses a direct offset into the object’s memory.
The speed difference is roughly 10-20% for attribute access. In practice, this only matters in extremely hot loops — the memory savings are usually the primary motivation.
Common Misconception
“slots makes my class immutable.” No. Slotted attributes are still fully mutable — you just can’t add new ones. You can change point.x freely; you just can’t add point.z.
For actual immutability, use @dataclass(frozen=True) or NamedTuple.
When to Use slots
✅ You’re creating many instances of the same class (thousands+) ✅ You know all the attributes at design time ✅ Memory profiling shows object overhead is significant ✅ You’re building data containers with fixed schemas
When to Skip Them
❌ You have few instances ❌ You need dynamic attributes (plugin systems, monkey-patching) ❌ You’re subclassing classes without slots (benefit is lost) ❌ You’re using dataclasses or NamedTuples (they handle optimization differently)
One thing to remember: __slots__ is a memory optimization, not a design pattern. Profile first, slot second. When you have millions of objects with known attributes, it’s one of the easiest wins in Python.
See Also
- Python Algorithmic Complexity Understand Algorithmic Complexity through a practical analogy so your Python decisions become faster and clearer.
- Python Async Performance Tuning Making your async Python faster is like organizing a busy restaurant kitchen — it's all about flow.
- Python Benchmark Methodology Why timing Python code once means nothing, and how fair testing works like a science experiment.
- Python C Extension Performance How Python borrows C's speed for the hard parts — like hiring a specialist for the toughest job on the worksite.
- Python Caching Strategies Understand Python caching strategies with a shortcut-road analogy so your app gets faster without taking wrong turns.