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.

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.

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:
- Use Python Class Constructors with Parameters
- Call a Base Class Constructor with Arguments in Python
- Check if an Object is Iterable in Python
- How to Use Private Variables in Python for Data Hiding

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.