Python

Saving Memory in Python with `__slots__`

Learn how Python's `__slots__` reduces memory overhead by replacing per-instance dictionaries with fixed-size arrays, with benchmarks and when to use it.

August 2026 5 min read 13 views 0 hearts

If you've been working with Python for a while, you know that objects can be quite memory-hungry. Every time you create a class instance, Python allocates a dictionary (__dict__) to hold its attributes. This dictionary is flexible but comes at a cost—sometimes a big one, especially when you're creating thousands or millions of objects.

That's where __slots__ comes in. It's a simple feature that can dramatically reduce memory usage in your Python programs. Let me walk you through what it does and when you should use it.

The Problem: Python's Default Object Storage

When you create a typical class in Python, each instance carries around a dictionary for attribute storage:

class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

user = User("Pythonskillset", "contact@pythonskillset.com")
print(user.__dict__)
# Output: {'name': 'Pythonskillset', 'email': 'contact@pythonskillset.com'}

This dictionary is powerful—you can add, remove, or change attributes dynamically. But dictionaries are heavy. Each dictionary takes up significant memory, and for objects with a fixed set of attributes, this overhead is wasteful.

The Solution: __slots__

When you define __slots__, Python tells the interpreter to store attributes in a fixed-size array instead of a dictionary. No dictionary, no overhead. Here's the same class using slots:

class User:
    __slots__ = ('name', 'email')

    def __init__(self, name, email):
        self.name = name
        self.email = email

user = User("Pythonskillset", "contact@pythonskillset.com")
print(hasattr(user, '__dict__'))
# Output: False

By defining __slots__, you're telling Python: "These are the only attributes this class will ever have." No dictionary is created, no extra memory is wasted.

How Much Memory Does It Save?

Let's test this with a real benchmark. We'll create a million user objects to see the difference:

import sys

class UserSlots:
    __slots__ = ('name', 'email')
    def __init__(self, name, email):
        self.name = name
        self.email = email

class UserNoSlots:
    def __init__(self, name, email):
        self.name = name
        self.email = email

# Create one instance of each
slots_user = UserSlots("test", "test@example.com")
no_slots_user = UserNoSlots("test", "test@example.com")

print(f"Size with __slots__: {sys.getsizeof(slots_user)} bytes")
print(f"Size without __slots__: {sys.getsizeof(no_slots_user)} bytes")

You'll typically see a difference of about 40-60 bytes per object. That might not sound like much, but when you scale up to millions of objects, it can mean saving hundreds of megabytes of RAM.

When Should You Use __slots__?

Slots aren't always the right choice. Here's when they shine:

  • Large numbers of objects - If you're creating thousands or millions of instances, slots can save significant memory
  • Fixed attribute sets - When you know exactly what attributes an object will have and they're not changing
  • Data-heavy applications - Data processing pipelines, game engines, or scientific computing where memory matters
  • High-performance scenarios - Slots also give you faster attribute access (about 10-15% faster in some cases)

When to Avoid __slots__

  • Dynamic attributes - If you need to add attributes on the fly, slots won't work
  • Small number of objects - For just a few instances, the memory savings are negligible
  • Inheritance complexity - Subclasses that use slots can get tricky (more on this below)
  • When using __dict__ directly - Some libraries or frameworks expect objects to have a __dict__

The Inheritance Gotcha

Slots don't work automatically with inheritance. If a parent class uses slots and you create a subclass without them, the subclass will fall back to using dictionaries anyway:

class Base:
    __slots__ = ('x',)

class Child(Base):
    pass  # This will have __dict__ again!

child = Child()
child.y = 10  # Works fine because __dict__ exists

If you want to maintain slot behavior in subclasses, you need to be explicit:

class Child(Base):
    __slots__ = ('y',)  # Must add slots for new attributes

child = Child()
# child.z = 10  # This would fail - AttributeError

Real-World Example at Pythonskillset

At Pythonskillset, we recently optimized a data processing pipeline that handled millions of user activity records. Each record was stored as a small Python object with fixed fields (user_id, action, timestamp, duration). By switching to __slots__, we reduced memory usage by roughly 60% and saw a measurable improvement in processing speed. The change took about 10 minutes to implement.

Final Thoughts

__slots__ is one of those Python features that's easy to overlook but incredibly valuable in the right situations. It's not a silver bullet—you still need to understand when it makes sense—but for memory-sensitive applications, it's a tool you should know well.

Remember: Python's flexibility is its strength, but that flexibility comes with costs. Knowing when to tighten things down with __slots__ is part of writing efficient, professional Python code.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.