Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
134: Slots for Memory-Efficient Classes
Why should I care about slots if my classes already work?
In most of your daily coding, you won't notice a thing. But here is the deal: by default, Python stores instance attributes in a dictionary called __dict__. Dictionaries are great because they're flexible—you can slap a new attribute onto an object whenever you feel like it. The problem is that dictionaries have a significant memory overhead.
Imagine you're building a system to track millions of GPS coordinates for a fleet of delivery drones. If each Coordinate object has its own __dict__, you're wasting a massive amount of RAM just on the dictionary structure itself, not the actual data. That's where __slots__ comes in. It tells Python, "I know exactly which attributes this class will have; don't bother creating a dictionary."
import sys
class Coordinate:
__slots__ = ('lat', 'lon') # This is the magic line
def __init__(self, lat, lon):
self.lat = lat
self.lon = lon
# Now Python allocates a small, fixed amount of space for each instance
# instead of a dynamic hash map.
How much of a difference does this actually make in memory?
It's often surprising. I've seen cases where switching to slots reduced memory usage by 40% to 60%. Because Python no longer needs to store the keys for every single instance, the memory footprint drops significantly. Plus, you get a slight bump in attribute access speed because Python can use a more direct offset to find the value in memory rather than performing a hash map lookup.
I usually only reach for this when I know I'm instantiating thousands—or millions—of the same object. If you're just making a few configuration objects for your app, stick to the defaults. The flexibility of __dict__ is usually worth more than a few kilobytes of saved RAM.
Does this mean I can't add new attributes on the fly anymore?
Exactly. That is the price you pay for the efficiency. When you define __slots__, you are locking down the object. If you try to assign an attribute that isn't listed in your slots, Python will throw an AttributeError.
coord = Coordinate(40.7128, -74.0060)
coord.lat = 40.7129 # This works fine
# But wait, I want to add a label to this specific coordinate...
try:
coord.label = "NYC Office"
except AttributeError as e:
print(f"Error: {e}") # Output: 'Coordinate' object has no attribute 'label'
I've seen developers try to "cheat" by adding '__dict__' to the slots list. While that works and gives you the best of both worlds (fixed slots for some, a dict for others), it completely defeats the purpose of memory optimization. If you find yourself needing dynamic attributes, you probably shouldn't be using slots in the first place.
What happens if I use slots in a class hierarchy?
This is where things get a bit trippy. If you have a base class with __slots__ and a subclass that doesn't define them, the subclass will still have a __dict__. This means your memory savings vanish the moment you inherit from a slotted class without also slotting the child.
To keep the memory efficiency flowing down the chain, every single class in the inheritance line needs to define __slots__. Even if the subclass doesn't add any new attributes, you should define __slots__ = () to ensure it doesn't accidentally create a __dict__.
📋 Practical Task
Optimizing a High-Frequency Sensor Log
You are writing a script to process a massive log file containing millions of sensor readings. Each reading has a sensor_id (integer), a value (float), and a timestamp (float). Your current implementation is crashing the server due to an Out-Of-Memory (OOM) error.
Your task:
- Create a class named
SensorReadingthat uses__slots__to minimize memory usage. - Ensure it supports
sensor_id,value, andtimestamp. - Initialize these values in the
__init__method. - Write a small test script that instantiates one
SensorReadingand attempts to assign a new attributeself.unit = "Celsius"to it. Wrap this in atry/exceptblock to verify that theAttributeErroris raised, proving your slots are working.
There are no comments for now.