← Back to Python

__slots__

PythonSeniorpython

The Question

What are __slots__ and why would you use them?

What a Strong Answer Covers

  • prevents __dict__
  • "less memory
  • "no dynamic attributes

Senior-Level Answer

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.

What Separates a 2/3 from a 3/3

2/3 — Passing but Incomplete

Explains that __slots__ replaces __dict__ with a fixed array, states the memory and speed benefits with rough magnitude, and names one concrete caveat.

3/3 — Strong Answer

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.

Common Mistakes

  • Claiming __slots__ is just for preventing dynamic attribute addition — that's a side effect, not the purpose
  • Missing the inheritance caveat — one unsotted parent silently re-introduces __dict__
  • Overstating the benefit for small numbers of instances where the overhead is negligible
  • Not knowing that dataclasses support slots natively since Python 3.10

Follow-Up Questions

  • If a parent class doesn't define __slots__, what happens when a child class does? — The child gets both its slots and __dict__ from the parent — the memory optimization is lost.
  • How would you measure whether __slots__ is actually helping in your application? — Use memory_profiler, tracemalloc, or sys.getsizeof() to measure before/after. Profile at scale — the delta matters per-instance count.
  • Can you add __dict__ to __slots__ explicitly, and why would you? — Yes — it opts back into dynamic attributes while still getting slots for declared names. Rarely useful; mostly a migration path.
  • How do attrs and dataclasses simplify working with __slots__? — @attr.s(slots=True) and @dataclass(slots=True) create a new class with __slots__ behind the scenes, handling __weakref__, pickle, and inheritance correctly.

Related Questions

  • GIL — What It Is and What It Protects
  • ThreadPoolExecutor & ProcessPoolExecutor
  • Decorators — Under the Hood
  • Generators & yield
  • Context Managers

Can You Explain This Cold?

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
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout