I’ll help you understand **slots in Python**, which are a memory optimization feature for classes.

## What are Slots?

Slots (`__slots__`) allow you to explicitly declare data members (attributes) in a class and prevent the creation of `__dict__` and `__weakref__` for instances, saving memory.

slots pg

## Basic Example

“`python
class Person:
__slots__ = (‘name’, ‘age’)

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

# Usage
p = Person(“Alice”, 30)
print(p.name) # Alice
print(p.age) # 30

# This will raise AttributeError because ‘email’ is not in __slots__
# p.email = “[email protected]
“`

## Benefits of Using Slots

### 1. **Memory Efficiency**
“`python
import sys

class WithoutSlots:
def __init__(self, x, y):
self.x = x
self.y = y

class WithSlots:
__slots__ = (‘x’, ‘y’)
def __init__(self, x, y):
self.x = x
self.y = y

obj1 = WithoutSlots(1, 2)
obj2 = WithSlots(1, 2)

print(f”Without slots: {sys.getsizeof(obj1) + sys.getsizeof(obj1.__dict__)} bytes”)
print(f”With slots: {sys.getsizeof(obj2)} bytes”)
“`

### 2. **Faster Attribute Access**
Slots use a more efficient mechanism for attribute lookup.

## Important Considerations

### Inheritance with Slots
“`python
class Base:
__slots__ = (‘x’,)

class Derived(Base):
__slots__ = (‘y’,) # Adds ‘y’, inherits ‘x’ from Base

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

d = Derived(10, 20)
print(d.x, d.y) # 10 20
“`

### Multiple Inheritance with Slots
“`python
class A:
__slots__ = (‘a’,)

class B:
__slots__ = (‘b’,)

class C(A, B):
__slots__ = (‘c’,) # Must redeclare all parent slots

def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
“`

## When to Use Slots

✅ **Use slots when:**
– Creating many instances of a class (memory optimization)
– Class has a fixed set of attributes
– Performance is critical
– Working with data-oriented classes

❌ **Avoid slots when:**
– Need dynamic attribute assignment
– Using multiple inheritance with conflicting slots
– Need `__dict__` for serialization or other purposes
– Using mixins or complex inheritance hierarchies

## Complete Example with Properties

“`python
class Employee:
__slots__ = (‘_name’, ‘_salary’, ‘_id’)

def __init__(self, name, salary, emp_id):
self._name = name
self._salary = salary
self._id = emp_id

@property
def name(self):
return self._name

@property
def salary(self):
return self._salary

@salary.setter
def salary(self, value):
if value >= 0:
self._salary = value
else:
raise ValueError(“Salary cannot be negative”)

# Usage
emp = Employee(“John”, 50000, “E001”)
print(emp.name) # John
emp.salary = 55000 # Works
# emp.title = “Manager” # Error: ‘Employee’ object has no attribute ‘title’
“`

## Common Pitfalls

“`python
class Problematic:
__slots__ = (‘x’,)

def __init__(self):
self.x = 10

# This won’t work – can’t assign new attributes
def add_attribute(self):
# self.y = 20 # AttributeError
pass

slots pg

# Solution: Use a different approach if you need flexibility
class Flexible:
__slots__ = (‘x’, ‘y’, ‘z’) # Define all possible attributes

def __init__(self):
self.x = 10
# y and z can be set later if needed
“`

## Performance Comparison

“`python
import timeit

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

class Slotted:
__slots__ = (‘x’, ‘y’)
def __init__(self, x, y):
self.x = x
self.y = y

# Attribute access speed
regular_time = timeit.timeit(‘obj.x’,
setup=’obj = Regular(1, 2)’,
globals=globals())
slotted_time = timeit.timeit(‘obj.x’,
setup=’obj = Slotted(1, 2)’,
globals=globals())

print(f”Regular access: {regular_time:.6f}s”)
print(f”Slotted access: {slotted_time:.6f}s”)
“`

**Slots are a powerful optimization tool**, but use them judiciously. They’re excellent for data-heavy applications where you create many instances of a class with a fixed structure, but they reduce flexibility.