Slots & Hashing
Overview
Learn how slots optimizes class memory usage, and master custom class hashing protocols (hash and eq).
Learning Objectives
- Use slots to prevent default instance dict memory allocation.
- Make custom object instances hashable.
- Avoid hash keys lookups conflicts in sets.
Concept Explanation
Python objects store attributes inside dictionary dict buffers. Declaring __slots__ tells Python to use a fixed array instead, saving up to 70% memory. To use instances inside sets, override __eq__ and __hash__ correctly.
Code Examples
Example 1 — Basics
This example introduces the fundamental syntax and concepts.
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
Example 2 — Everyday Usage
This example demonstrates a realistic scenario handling business parameters.
class Node:
__slots__ = ('val', 'next')
def __init__(self, val):
self.val = val
self.next = None
# Node consumes significantly less memory when instantiated millions of times
Example 3 — Advanced Example
This example shows clean, production-grade code structure following senior development standards.
class UniqueKey:
def __init__(self, uid):
self.uid = uid
def __eq__(self, other):
if not isinstance(other, UniqueKey): return False
return self.uid == other.uid
def __hash__(self):
return hash(self.uid)
key1 = UniqueKey(1)
key2 = UniqueKey(1)
s = {key1}
print(key2 in s) # True! Hash matches and eq evaluates True
Visual Flow
The following execution flow represents the step-by-step evaluation inside the interpreter:
Instantiate slotted class → Pre-allocate array slots → Map attribute accesses directly by array indices
Common Mistakes
Review these common pitfalls when working with this topic:
- Trying to add dynamic attributes to slotted instances.
- Overriding eq without defining hash, which makes instances unhashable.
- Mutating attributes that are used inside hash collections calculations.
- Inheriting slotted classes from unslotted parents.
Best Practices
Enforce these Pythonic best practices in your codebase:
class Node:
def __init__(self, val):
self.val = val # Allocates dynamic __dict__ dictionary
class Node:
__slots__ = ('val', 'next')
def __init__(self, val):
self.val = val # Memory optimized slots
Performance Notes
Keep these optimization guidelines in mind for performance-sensitive hotpaths:
- slots reduces class instantiation memory usage by up to 60-70% by avoiding dict allocations.
- Attribute lookups are faster with slots because they bypass dictionary hash table searches.
Quick Revision
Use these key summaries for last-minute revision:
- slots avoids dictionary allocation in objects.
- Saves memory and speeds up lookups.
- Slotted objects cannot have dynamic attributes.
- Custom hash keys require eq and hash.
- Hash keys must remain constant.
- Overriding eq alone makes objects unhashable.