__slots__ — Leaner Objects
Declare a fixed set of attributes to cut memory use and catch typo-attributes early.
By default every Python instance stores its attributes in a per-instance __dict__ — flexible, but memory-hungry when you have millions of objects. Declaring __slots__ tells Python the exact attributes an instance will have, so it can skip the dictionary entirely.
class Point:
__slots__ = ('x', 'y') # no per-instance __dict__
def __init__(self, x, y):
self.x, self.y = x, y
p = Point(1, 2)
print(p.x, p.y) # 1 2
# p.z = 3 -> AttributeError: 'Point' object has no attribute 'z'Two real benefits
- Memory — slotted instances can use dramatically less RAM. At scale (data pipelines, simulations, ORMs) this is the difference between fitting in memory and not.
- Typo safety — assigning an attribute you never declared raises
AttributeErrorinstead of silently creating a misspelled field.
The trade-offs
Slotted classes cannot gain new attributes at runtime and, without care, do not play well with multiple inheritance or __dict__-based tricks. Use slots on small, numerous, well-defined objects — not on everything.
Example
When to use it
- A high-frequency trading system uses __slots__ on a Tick class to cut memory for millions of instances.
- A data model uses __slots__ to catch typos in attribute names at assignment time rather than silently creating new ones.
- A game engine's Particle class defines __slots__ to avoid the per-instance __dict__ overhead.
More examples
Define __slots__
Restricts the instance to exactly the declared slots; assigning an undeclared attribute raises AttributeError.
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y): self.x, self.y = x, y
p = Point(3, 4)
print(p.x, p.y) # 3 4
# p.z = 0 -> AttributeError: 'Point' has no attribute 'z'Memory comparison
Shows that __slots__ eliminates the instance __dict__, reducing memory for large numbers of objects.
import sys
class WithDict:
def __init__(self, x, y): self.x, self.y = x, y
class WithSlots:
__slots__ = ('x', 'y')
def __init__(self, x, y): self.x, self.y = x, y
a = WithDict(1, 2)
b = WithSlots(1, 2)
print(sys.getsizeof(a.__dict__)) # ~200 bytes
print(hasattr(b, '__dict__')) # False__slots__ in a subclass
Demonstrates __slots__ inheritance: each class declares only its own new attributes.
class Base:
__slots__ = ('x',)
def __init__(self, x): self.x = x
class Child(Base):
__slots__ = ('y',) # adds y, inherits x
def __init__(self, x, y):
super().__init__(x)
self.y = y
c = Child(1, 2)
print(c.x, c.y) # 1 2
Discussion