__slots__ and Memory Optimization
Use __slots__ to reduce per-instance memory overhead.
__slots__ and Memory Optimization is a free Python Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Default __dict__ Overhead
By default every Python instance stores attributes in a __dict__ dictionary, which has significant memory overhead — typically 200-400 bytes per instance.
import sys
class Point:
def __init__(self, x, y): self.x, self.y = x, y
p = Point(1, 2)
print(sys.getsizeof(p.__dict__)) # ~200 bytesDeclaring __slots__
Define __slots__ as a sequence of attribute names. Python allocates a fixed-size array instead of a dict, saving memory.
class SlottedPoint:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
p = SlottedPoint(1, 2)
print(p.x, p.y) # 1 2
# p.z = 3 # AttributeError: no __dict__Memory Savings
With __slots__, each instance typically saves 30-50% memory compared to a dict-based instance — significant when creating millions of objects.
import sys
class Reg:
def __init__(self, x, y): self.x, self.y = x, y
class Slotted:
__slots__ = ("x","y")
def __init__(self, x, y): self.x, self.y = x, y
print(sys.getsizeof(Reg(1,2))) # ~56 bytes + ~200 dict
print(sys.getsizeof(Slotted(1,2))) # ~56 bytes (no dict)No __dict__ by Default
A slotted class has no __dict__, so you cannot add arbitrary attributes after creation.
class Config:
__slots__ = ("host", "port")
def __init__(self, h, p): self.host, self.port = h, p
c = Config("localhost", 8080)
# c.debug = True # AttributeError
print(hasattr(c, "__dict__")) # FalseKeeping __dict__ with __slots__
Include "__dict__" in __slots__ to retain a per-instance dict while still pre-declaring common attributes as slots.
class Hybrid:
__slots__ = ("x", "__dict__")
def __init__(self, x):
self.x = x
h = Hybrid(1)
h.extra = "dynamic" # allowed
print(h.extra)__weakref__ in __slots__
Slotted classes lose weak-reference support. Add "__weakref__" to __slots__ to re-enable it.
import weakref
class Node:
__slots__ = ("value", "__weakref__")
def __init__(self, v): self.value = v
n = Node(42)
ref = weakref.ref(n)
print(ref()) # <Node object>Inheritance and __slots__
If a parent class does not use __slots__, the child still gets a __dict__. For full savings, the entire hierarchy must define __slots__.
class Base:
__slots__ = ("x",)
class Child(Base):
__slots__ = ("y",) # no __dict__
class WithoutSlots(Base):
pass # gets __dict__ from objectBenchmarking Memory
Use tracemalloc or pympler to measure actual memory usage before and after adding __slots__.
import tracemalloc
tracemalloc.start()
points = [SlottedPoint(i, i) for i in range(100_000)]
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"Peak: {peak/1024/1024:.1f} MB")__slots__ and Pickling
Slotted objects can be pickled if you define __getstate__ and __setstate__ or use the default pickle protocol which handles slots automatically from Python 3.
import pickle
class Point:
__slots__ = ("x", "y")
def __init__(self, x, y): self.x, self.y = x, y
p = Point(3, 4)
data = pickle.dumps(p)
p2 = pickle.loads(data)
print(p2.x, p2.y) # 3 4dataclasses with __slots__ — Python 3.10+
Pass slots=True to @dataclass to automatically generate __slots__.
from dataclasses import dataclass
@dataclass(slots=True)
class Vector:
x: float
y: float
v = Vector(1.0, 2.0)
print(v.x, v.y) # 1.0 2.0
print(hasattr(v, "__dict__")) # FalseWhen to Use __slots__
Use __slots__ when: creating millions of instances, memory is constrained, or attribute-access speed is critical. Skip it for general-purpose classes where flexibility matters more.
# Good candidates:
# - Nodes in a large graph or tree
# - Records in a large dataset
# - High-frequency event objects
# Bad candidates:
# - Configuration objects added to ad-hoc
# - Classes that mix-in dynamic attributesQuick Check
What happens when you try to set an attribute not listed in __slots__ on a slotted instance?
Recap
__slots__ replaces the per-instance __dict__ with a fixed array, saving 30-50% memory. Include "__dict__" or "__weakref__" if you need them. The entire inheritance chain must use __slots__ for full savings. In Python 3.10+ use @dataclass(slots=True).
Frequently asked questions
Is the “__slots__ and Memory Optimization” lesson free?
Yes — the full text of “__slots__ and Memory Optimization” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.
What will I learn in “__slots__ and Memory Optimization”?
Use __slots__ to reduce per-instance memory overhead. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Python Academy?
No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “__slots__ and Memory Optimization” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Python Academy lesson?
Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- How Python Classes Are Created
- Writing Custom Metaclasses
- Descriptors: __get__, __set__, __delete__
- __slots__ and Memory Optimization