__slots__ & Memory Optimization

__slots__ is a class declaration that lists exactly which attributes instances may have, letting Python drop the per-instance __dict__ and store those attributes in fixed slots — making each object smaller and attribute access a touch faster.

Learn __slots__ & Memory Optimization in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

When you create millions of small objects, the hidden __dict__ on every instance dominates your memory use. __slots__ trades a little flexibility for substantial savings — the right tool when you have many instances and few attributes.

By default, Python stores an object's attributes in a dictionary attached to each instance — __dict__ . It's flexible (you can add any attribute, anytime) but every instance pays the cost of that dictionary:

That dictionary is convenient, but for one or two attributes it's a lot of overhead — and it repeats for every single instance you create.

Add a class-level __slots__ listing your attribute names and Python reserves fixed storage for exactly those — and removes __dict__ entirely:

The class behaves the same from the outside — you still write p.x — but each instance is now leaner because there's no dictionary riding along. The attributes live in compact, fixed slots instead.

Here's the trade-off. Without a __dict__ , you can't tack on attributes that aren't in __slots__ . Trying to do so raises AttributeError :

sys.getsizeof reports an object's size in bytes. A regular instance is small on its own, but it drags along a separate __dict__ — so the true cost is the instance plus its dictionary. A slotted instance has no such dictionary:

One object: irrelevant. A million objects: the __dict__ overhead can be hundreds of megabytes. Slots shine for data-heavy structures — graph nodes, simulation particles, parsed records:

Python 3.10+ generates the slots for you when you ask a dataclass for them:

Complete the class so it stores only lat and lon with no __dict__ . Replace each ___ , then run it.

❌ A single string instead of a tuple of names

✅ Always use a tuple (or list) of strings, even for one slot:

✅ Add it to __slots__ , or if you truly need dynamic attributes, include "__dict__" in the slots (which gives back the dictionary and most of the savings are lost).

❌ Expecting cached_property to work with slots

✅ Slots remove __dict__ , which cached_property relies on. Use a plain @property , or don't slot that class.

Build a slotted Vec2 with x and y and a length method, prove it has no __dict__ , and confirm an undeclared attribute is rejected.

Lesson complete — you can optimize memory now!

You understand the per-instance __dict__ , how __slots__ drops it for smaller, faster objects, the no-new-attributes restriction, how to measure with sys.getsizeof , and when slots are worth it. Use them deliberately, at scale.

🚀 Up next: Scope — global, nonlocal & LEGB — master where your names live.

Practice quiz

What does declaring __slots__ on a class do to its instances?

  • It removes the per-instance __dict__ and stores attributes in fixed slots
  • It makes every attribute read-only
  • It automatically adds a __dict__ to each instance
  • It speeds up class creation but not attribute access

Answer: It removes the per-instance __dict__ and stores attributes in fixed slots. __slots__ reserves fixed storage for the listed attributes and drops the per-instance __dict__, making instances smaller.

After class Point: __slots__ = ('x','y'), what is hasattr(Point(1,2), '__dict__')?

  • True
  • False
  • It raises AttributeError
  • None

Answer: False. A fully slotted class has no per-instance __dict__, so hasattr returns False.

What happens when you assign an attribute that is NOT listed in __slots__?

  • It is silently added to a hidden __dict__
  • It works but uses extra memory
  • It raises AttributeError
  • It raises TypeError

Answer: It raises AttributeError. Without a __dict__, assigning an undeclared attribute raises AttributeError — the restriction is the whole point.

Why is __slots__ described as a memory optimization?

  • It compresses attribute values
  • It eliminates the per-instance dictionary, which matters across many instances
  • It shares attributes between all instances
  • It moves attributes to disk

Answer: It eliminates the per-instance dictionary, which matters across many instances. Dropping the __dict__ on every instance saves memory that multiplies across millions of small objects.

Which is the correct way to declare a single slot?

  • __slots__ = 'x'
  • __slots__ = ('x',)
  • x

Answer: __slots__ = ('x',). Use a tuple (note the trailing comma). A bare string is iterated character by character, which breaks for multi-letter names.

Since which Python version can a dataclass generate slots with @dataclass(slots=True)?

  • 3.6
  • 3.8
  • 3.10
  • 2.7

Answer: 3.10. @dataclass(slots=True) was added in Python 3.10, generating a slotted class automatically.

Which function reports an object's size in bytes for measuring savings?

  • len()
  • sys.getsizeof()
  • id()
  • sys.getrefcount()

Answer: sys.getsizeof(). sys.getsizeof reports an object's size in bytes; a slotted instance has no separate __dict__ to add to the total.

Why does @cached_property typically fail on a slotted class?

  • cached_property is deprecated
  • It needs a writable __dict__ to store the cache, which slots remove
  • It only works on functions, not methods
  • Slots make all attributes immutable

Answer: It needs a writable __dict__ to store the cache, which slots remove. cached_property stores its cached value in the instance __dict__, which a fully slotted class does not have.

When is __slots__ MOST worth using?

  • When you have a handful of objects with many attributes
  • When you create a very large number of small instances with a fixed set of attributes
  • Whenever you define any class, as a habit
  • Only for classes that need dynamic attributes

Answer: When you create a very large number of small instances with a fixed set of attributes. Slots shine at scale: many instances and few, fixed attributes. For a few objects the savings are irrelevant.

How can you keep a __dict__ AND use __slots__ if you truly need dynamic attributes?

  • Include '__dict__' in the __slots__ tuple
  • It is impossible to combine them
  • Set __slots__ = None
  • Use @property on every attribute

Answer: Include '__dict__' in the __slots__ tuple. Adding '__dict__' to __slots__ gives back the dictionary, but most of the memory savings are then lost.