__slots__ is a special class attribute that limits the set of allowed instance attributes, saves memory, and speeds up attribute access. Using __slots__ is especially relevant for a large number of similar objects.
History of the issue:
The appearance of __slots__ is related to the fact that by default, each Python object instance has an attribute dictionary (__dict__), which is convenient but memory-intensive. For a million objects with a small set of fields, there is significant overhead.
Problem:
Instances of a regular class can dynamically expand, which is convenient but inefficient. Applying __slots__ limits the dynamic addition of new attributes, removes the instance attribute dictionary, saves memory, and speeds up access.
Solution:
Describe the list of allowed fields in the __slots__ attribute:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
Key features:
Can you create an instance of a class with slots and then add an attribute not from the list?
No. Attempting to add an attribute not in the slots list will raise an AttributeError. This places limitations on the extensibility of the object.
Can you inherit from a class with slots and add new fields?
Yes, but each subclass must declare its own slots. In this case, parent and current slots are combined. However, if slots are not declared in the subclass, the descendant will have dict again!
Does slots work for immutable types?
Yes, but additional measures must be implemented to make the slot object immutable (for example, via property without a setter).
A regular class for a point:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Pros:
Cons:
An analogous class but with slots:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Pros:
Cons: