Slots
__slots__ is a class attribute that reserves memory for listed instance variables and prevents the creation of __dict__, significantly reducing memory footprint.
Basic Usage
Without __slots__, each instance has a __dict__:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.__dict__) # {'x': 1, 'y': 2}
# With __slots__ - no __dict__
class Point:
__slots__ = ['x', 'y']
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.__dict__) # AttributeError!
Memory Savings
__slots__ can reduce memory usage by 40-50%:
import sys
class WithoutSlots:
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
class WithSlots:
__slots__ = ['a', 'b', 'c', 'd']
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
# Create instances
without = WithoutSlots(1, 2, 3, 4)
with_slots = WithSlots(1, 2, 3, 4)
print(sys.getsizeof(without.__dict__)) # ~100+ bytes (dict)
print(sys.getsizeof(with_slots.__slots__)) # Much less!
Inheritance with Slots
Subclasses need their own __slots__:
class Base:
__slots__ = ['x']
class Derived(Base):
__slots__ = ['y'] # Add more slots
d = Derived()
d.x = 1
d.y = 2
# d.z = 3 would raise AttributeError
# Without __slots__ in derived - has __dict__ again
class DerivedWithDict(Base):
pass # No __slots__ - gets __dict__ back
Multiple Inheritance
All parent classes must have __slots__:
class A:
__slots__ = ['a']
class B:
__slots__ = ['b']
class C(A, B):
__slots__ = ['c']
c = C()
c.a, c.b, c.c = 1, 2, 3
# Warning: both parents should have __slots__
# Otherwise C will have __dict__
Using Properties with Slots
Define computed properties alongside slots:
class Rectangle:
__slots__ = ['_width', '_height']
def __init__(self, width, height):
self._width = width
self._height = height
@property
def area(self):
return self._width * self._height
@property
def perimeter(self):
return 2 * (self._width + self._height)
r = Rectangle(3, 4)
print(r.area) # 12
print(r.perimeter) # 14
r._width = 5 # Can still modify
Weakref Support
Add __weakref__ for weak references:
import weakref
class Node:
__slots__ = ['value', '_parent', '__weakref__']
def __init__(self, value, parent=None):
self.value = value
self._parent = parent
n1 = Node(1)
n2 = Node(2, n1)
# Can create weak reference
ref = weakref.ref(n2)
print(ref().value) # 2
Slots Are Not Magic
Key limitations and considerations:
# Can't add new attributes not in __slots__
class Person:
__slots__ = ['name']
p = Person()
p.name = "Alice"
p.age = 30 # AttributeError!
# Class attributes still work
Person.motto = "Hello" # This works
print(Person.motto)
# Need to use slots in all subclasses to maintain benefits
class Employee(Person):
pass # Employee has __dict__ again!
When to Use Slots
| Use Case | Recommendation |
|---|---|
| Many instances (10k+) | Use __slots__ |
| Few instances | Not necessary |
| Dynamic attributes needed | Don't use __slots__ |
| Memory constrained | Use __slots__ |
| Simple data containers | Use __slots__ or dataclass |
Tip: dataclasses with
slots=True (Python 3.10+) gives you the best of both worlds.