Slots in Python

Loading

In Python, every object has a dynamic dictionary (__dict__) that stores its attributes. While flexible, this can consume more memory and slow down attribute access.

__slots__ helps reduce memory usage by preventing the creation of __dict__ and restricting attributes to a fixed set.
Improves attribute lookup speed by avoiding dictionary overhead.
Useful for performance optimization in applications with many instances.


1. Understanding __slots__

By default, Python classes use a dictionary (__dict__) to store attributes dynamically.

Example: Regular Class with __dict__

class Person:
def __init__(self, name, age):
self.name = name
self.age = age

p = Person("Alice", 30)
print(p.__dict__)
# Output: {'name': 'Alice', 'age': 30}

Problem:

  • Each instance has a __dict__, consuming extra memory.
  • Attribute lookup is slower due to dictionary overhead.

2. Using __slots__ to Optimize Memory Usage

The __slots__ attribute restricts instances to a fixed set of attributes and removes the __dict__.

Example: Defining __slots__

class Person:
__slots__ = ('name', 'age') # Restrict attributes

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

p = Person("Alice", 30)
print(p.name) # Output: Alice

# p.address = "NYC" # AttributeError: 'Person' object has no attribute 'address'

What happens here?

  • No __dict__ → Memory-efficient storage.
  • Restricted attributes → Only name and age are allowed.
  • Faster attribute access → Directly stored in a lightweight structure.

3. Comparing Memory Usage (__dict__ vs __slots__)

Using sys.getsizeof() to measure memory usage.

Example: Memory Comparison

import sys

class Regular:
def __init__(self, x):
self.x = x

class Slotted:
__slots__ = ('x')

def __init__(self, x):
self.x = x

r = Regular(10)
s = Slotted(10)

print(sys.getsizeof(r.__dict__)) # Output: 112 (dict overhead)
# print(s.__dict__) # AttributeError: No __dict__ (saves memory)

Why does __slots__ save memory?

  • Regular class: Stores attributes in a dictionary (__dict__), which has overhead.
  • Slotted class: Uses a tuple-like structure (lower memory footprint).

4. When to Use __slots__

Use __slots__ when:

  • You need thousands/millions of objects (e.g., data-heavy applications).
  • Memory optimization is a priority.
  • Your class has fixed attributes (no dynamic attributes needed).

Avoid __slots__ when:

  • You require dynamic attributes (e.g., adding attributes at runtime).
  • You need multiple inheritance (not well-supported with __slots__).
  • You frequently use dir(), vars(), or other reflection methods (which rely on __dict__).

5. Inheritance and __slots__

5.1 Single Inheritance with __slots__

When a subclass inherits a slotted class, it can define new slots.

class Parent:
__slots__ = ('a',)

class Child(Parent):
__slots__ = ('b',)

obj = Child()
obj.a = 10
obj.b = 20

# obj.c = 30 # AttributeError: 'Child' object has no attribute 'c'

Each class must define its own __slots__ for new attributes.


5.2 __slots__ with Multiple Inheritance (Limitations)

Python does not allow multiple slotted parent classes without a fallback __dict__.

class A:
__slots__ = ('x',)

class B:
__slots__ = ('y',)

class C(A, B): # Error: Multiple inheritance with slots
pass

Solution: Use __slots__ = ('x', 'y') in C OR avoid __slots__ in multiple-inheritance scenarios.


6. Allowing __dict__ with __slots__

If needed, you can explicitly allow dynamic attributes while keeping __slots__ benefits.

class Config:
__slots__ = ('setting1', 'setting2', '__dict__')

cfg = Config()
cfg.setting1 = "ON"
cfg.new_attr = "Allowed" # Now works, because __dict__ is present

Why?

  • __dict__ is re-enabled, allowing dynamic attributes.
  • __slots__ still optimizes existing attributes.

7. Summary Table

FeatureWithout __slots__With __slots__
Memory UsageHigher (uses __dict__)Lower (no __dict__)
Attribute AccessSlower (dictionary lookup)Faster (direct access)
Dynamic AttributesAllowedNot allowed (unless __dict__ is explicitly added)
Multiple InheritanceWorks normallyLimited support
Reflection (dir(), vars())Works as expectedMay not work correctly

Leave a Reply

Your email address will not be published. Required fields are marked *