How to Use Python slots to Optimize Memory Performance

I’ve been writing Python code for over a decade now. In the early days, I never really worried about how much RAM my objects were eating up.

But then I started working on a high-frequency trading platform in New York. We were dealing with millions of transaction objects every second, and our servers were hitting memory limits fast.

That is when I truly discovered the power of __slots__. It’s one of those “hidden” Python features that can instantly cut your memory footprint by 60% or more.

If you are building applications that handle massive amounts of data, such as processing census records or managing a fleet of IoT devices, you need to understand how this works.

What exactly are slots in Python?

By default, Python is very flexible. When you create a class, Python stores all its attributes in a hidden dictionary called __dict__.

This is great because it allows you to add new variables to an object on the fly. However, dictionaries are “heavy” and consume a lot of memory because they need extra space to handle potential growth.

When you define __slots__, you are essentially telling Python: “Hey, I know exactly what attributes this class will have. Don’t bother creating a dictionary.”

Python then allocates a fixed, small amount of space for only those attributes. It’s like switching from a bulky suitcase to a slim, fitted backpack.

The Memory Difference: A Real-World Comparison

To show you how much of a difference this makes, let’s look at a scenario involving a US-based logistics company.

Suppose we are tracking a fleet of delivery trucks across the United States. We need to store the latitude, longitude, and a unique vehicle ID for 1 million trucks.

Here is the full code to compare a standard class versus a slotted class:

import sys
import timeit

# Standard class using the default __dict__
class DeliveryTruckStandard:
    def __init__(self, truck_id, lat, lon):
        self.truck_id = truck_id
        self.lat = lat
        self.lon = lon

# Optimized class using __slots__
class DeliveryTruckSlotted:
    __slots__ = ['truck_id', 'lat', 'lon']
    def __init__(self, truck_id, lat, lon):
        self.truck_id = truck_id
        self.lat = lat
        self.lon = lon

# Let's test the memory usage
truck_std = DeliveryTruckStandard("TRK-1001", 40.7128, -74.0060)
truck_slot = DeliveryTruckSlotted("TRK-1001", 40.7128, -74.0060)

print(f"Standard Object Memory: {sys.getsizeof(truck_std)} bytes")
# Note: sys.getsizeof doesn't always show the dict size, so we check the dict specifically
print(f"Standard Dict Memory: {sys.getsizeof(truck_std.__dict__)} bytes")
print(f"Slotted Object Memory: {sys.getsizeof(truck_slot)} bytes")

# Speed Test: Accessing attributes
std_time = timeit.timeit(lambda: truck_std.lat, number=1000000)
slot_time = timeit.timeit(lambda: truck_slot.lat, number=1000000)

print(f"\nTime to access attribute (1M times) - Standard: {std_time:.4f}s")
print(f"Time to access attribute (1M times) - Slotted: {slot_time:.4f}s")

I executed the above example code and added the screenshot below.

Python slots to Optimize Memory Performance

When I ran this on my local machine, the memory savings were massive. The standard dictionary approach for a single object often uses triple the memory of the slotted version.

When you scale that to a million objects, you are talking about saving hundreds of megabytes of RAM.

How to Use Slots with Inheritance

Inheritance can be a bit tricky when you start using slots. I learned this the hard way during a project for a California-based real estate firm.

If you have a base class with slots and a child class that doesn’t define them, Python will automatically create a __dict__ for the child.

This completely negates the memory benefits you were trying to achieve.

To keep things optimized, you must define __slots__ in the child class as well, even if it’s just an empty tuple.

class Vehicle:
    __slots__ = ('vin', 'make')
    def __init__(self, vin, make):
        self.vin = vin
        self.make = make

class ElectricTruck(Vehicle):
    # We must define slots here too!
    __slots__ = ('battery_capacity',)
    def __init__(self, vin, make, battery_capacity):
        super().__init__(vin, make)
        self.battery_capacity = battery_capacity

# Testing the child class
tesla_semi = ElectricTruck("5YJSA1", "Tesla", "500kWh")
print(f"Attributes in slots: {tesla_semi.__slots__}")

# This will raise an AttributeError because __dict__ doesn't exist
try:
    tesla_semi.new_attr = "Error"
except AttributeError as e:
    print(f"Caught expected error: {e}")

I executed the above example code and added the screenshot below.

How to Use Python slots to Optimize Memory Performance

In this example, the ElectricTruck inherits the slots from Vehicle and adds its own. Because we explicitly defined __slots__ in both, we maintain that slim memory profile.

Common Issues and When to Avoid Slots

While I love using slots, they aren’t a “silver bullet” for every situation. There are a few trade-offs you need to consider before refactoring your entire codebase.

First, you lose the ability to add dynamic attributes. In standard Python, I can do obj.new_variable = 10 at any time. With slots, you can only use the variables you declared upfront.

Second, multiple inheritance with slots is a nightmare. If you try to inherit from two different slotted classes that both have non-empty slots, Python will raise a TypeError.

I usually follow this rule of thumb: If I’m creating a few dozen instances of a class, I stick with the standard dictionary. If I’m creating thousands (or millions), I switch to __slots__.

Use slots with Dataclasses

If you are using Python 3.10 or newer, you probably use dataclasses quite often. They are fantastic for boilerplate reduction.

The good news is that you don’t have to choose between dataclasses and memory optimization. You can pass slots=True to the decorator.

from dataclasses import dataclass

@dataclass(slots=True)
def EmployeeRecord:
    name: str
    emp_id: int
    office_location: str

# This employee object is now memory-optimized automatically!
emp = EmployeeRecord("Alice Smith", 402, "Chicago")

I find this to be the cleanest way to write modern Python code. It gives you the readability of dataclasses with the performance of slotted classes.

Conclusion

Using __slots__ is a easy way to make your Python applications leaner and faster. It is especially useful when you are dealing with large datasets or resource-constrained environments.

I hope you found this tutorial useful. If you are working on a project where memory management is a priority, give slots a try and see how much RAM you can save.

You may also like to read:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.