Python __slots__ Method
Last modified April 8, 2025
This comprehensive guide explores Python's __slots__ attribute, a
special class variable that optimizes memory usage and restricts attribute
creation. We'll cover basic usage, memory benefits, inheritance, and practical
examples.
Basic Definitions
The __slots__ class variable is used to explicitly declare instance
attributes. It serves two main purposes: memory optimization and attribute
restriction. When defined, it prevents the creation of __dict__.
Key characteristics: it must be a sequence (usually tuple) of strings, saves memory by avoiding per-instance dictionaries, and restricts dynamic attribute creation. It's particularly useful for classes with many instances.
Basic __slots__ Implementation
Here's the simplest implementation showing how __slots__ restricts
attribute creation and optimizes memory usage. It demonstrates the core behavior.
class Point:
    __slots__ = ('x', 'y')
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
p = Point(3, 4)
print(p.x, p.y)  # Works fine
# p.z = 5  # Raises AttributeError
This example shows a Point class with fixed attributes x and y. Attempting to
create a new attribute z would raise an AttributeError. The class doesn't have
a __dict__ attribute.
The memory savings come from not having a per-instance dictionary to store attributes. Instead, attributes are stored in a more compact internal structure.
Memory Optimization with __slots__
__slots__ significantly reduces memory usage for classes with many
instances. This example demonstrates the memory difference with and without it.
import sys
class RegularPoint:
    def __init__(self, x, y):
        self.x = x
        self.y = y
class SlotPoint:
    __slots__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y
regular = RegularPoint(3, 4)
slot = SlotPoint(3, 4)
print(sys.getsizeof(regular) + sys.getsizeof(regular.__dict__))
print(sys.getsizeof(slot))  # Typically much smaller
The SlotPoint class uses significantly less memory than RegularPoint. The difference becomes more noticeable when creating thousands or millions of instances.
Memory savings come from two sources: no __dict__ allocation and
more efficient attribute storage. The exact savings depend on Python version.
Inheritance with __slots__
When using inheritance with __slots__, special care must be taken.
Child classes must declare their own __slots__ to add new attributes.
class Base:
    __slots__ = ('a',)
    
class Child(Base):
    __slots__ = ('b',)  # Only contains 'b', 'a' is from parent
    
    def __init__(self, a, b):
        self.a = a
        self.b = b
obj = Child(1, 2)
print(obj.a, obj.b)
# obj.c = 3  # Raises AttributeError
The Child class inherits from Base but adds its own attribute b. The combined
slots are a and b. Without declaring __slots__ in Child, instances
would get __dict__.
If a child class doesn't define __slots__, it will behave like a
regular class with __dict__, losing the memory optimization.
Using __slots__ with Weak References
If you need weak references with __slots__, you must explicitly
include '__weakref__' in the slots declaration. This example shows
how.
import weakref
class WeakRefable:
    __slots__ = ('__weakref__', 'data')
    
    def __init__(self, data):
        self.data = data
obj = WeakRefable(42)
r = weakref.ref(obj)
print(r().data)  # 42
By including '__weakref__' in __slots__, we enable
weak reference support while still maintaining memory optimization. Without it,
weakref.ref() would raise TypeError.
This is necessary because __slots__ replaces the default mechanism
that normally provides weak reference support. The slot must be explicitly added.
Combining __slots__ with Properties
__slots__ works well with properties, allowing controlled attribute
access while still benefiting from memory optimization. Here's an example.
class Temperature:
    __slots__ = ('_celsius',)
    
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @property
    def fahrenheit(self):
        return (self._celsius * 9/5) + 32
temp = Temperature(25)
print(temp.fahrenheit)  # 77.0
# temp._celsius = 30  # Works (but underscore indicates "private")
This Temperature class uses __slots__ for memory efficiency while
providing property-based access to temperature values. The internal _celsius
attribute is stored in the slots structure.
Properties don't need to be listed in __slots__ as they're class
attributes, not instance attributes. Only data attributes need slots entries.
Best Practices
- Use for memory-critical applications: When creating many instances
- Document slot attributes: Clearly document all allowed attributes
- Consider inheritance carefully: Child classes need their own __slots__
- Add __weakref__ if needed: For weak reference support
- Don't use prematurely: Only optimize after profiling shows need
Source References
Author
List all Python tutorials.