What are __slots__ and why would you use them?
By default, every Python instance stores its attributes in a per-instance dictionary (`__dict__`). This dictionary is flexible — you can add arbitrary attributes at runtime — but it carries significant overhead: a dict object requires ~200-300 bytes of baseline memory, plus the hash table's load factor means it's often sparse.
`__slots__` replaces `__dict__` with a compact, fixed-size array of slot descriptors defined at class creation time. You declare it as a class variable:
```python class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y ```
When Python sees `__slots__`, it creates a descriptor for each slot name on the class and skips allocating `__dict__` for instances. Attribute access resolves through the descriptor protocol directly to a memory offset, rather than a dict lookup.
The two concrete benefits are memory and speed. Memory reduction is typically 40-60% per instance. For a class with two float attributes, a slotted instance uses ~56 bytes vs ~360 bytes with `__dict__`. Speed improvement on attribute get/set is ~15-30% due to eliminating hash computation.
Critical caveats:
**Inheritance:** If any class in the MRO omits `__slots__`, the `__dict__` is re-introduced by that parent. For the optimization to hold, every class in the inheritance chain must declare `__slots__`. This includes explicitly setting `__slots__ = ()` on intermediary base classes.
**Pickling and `__weakref__`:** Slotted classes cannot be weakly referenced unless `'__weakref__'` is included in `__slots__`. Pickling requires either `__getstate__`/`__setstate__` or including `'__dict__'` in slots (which defeats most of the memory benefit).
**No dynamic attributes:** You cannot add undeclared attributes to slotted instances at runtime. This is a behavioral change, not just an optimization.
**dataclasses and attrs:** Both support slots via `@dataclass(slots=True)` (Python 3.10+) and `@attr.s(slots=True)`, which handle the implementation details including inheritance and pickle support.
Use `__slots__` when you're creating millions of instances (e.g., nodes in a graph, event objects, parsed records from a large dataset) and memory profiling confirms `__dict__` overhead is significant. Do not use it speculatively — it adds complexity and removes flexibility.
Explains that __slots__ replaces __dict__ with a fixed array, states the memory and speed benefits with rough magnitude, and names one concrete caveat.
Covers the __dict__ replacement mechanism, quantifies benefits, explains the inheritance pitfall precisely (MRO requirement), discusses weakref/pickle constraints, and knows the dataclass(slots=True) shorthand.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment