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
230: Collections Module: namedtuple
I've seen this pattern in almost every codebase I've touched: a developer needs to group a few pieces of related data together, and they reach for a standard tuple because it's fast and easy. It seems fine in the moment, but as the project grows, those tuples become "mystery meat" objects. You'll see code like if transaction[2] == 'COMPLETED': and you'll find yourself scrolling up through five different functions just to remember what index 2 actually represents.
The fragility of magic indices
Let's say we're building a system to track server health checks. The naive approach is to store the results in a simple tuple: (hostname, status_code, response_time). It looks clean when you first write it:
# The naive way
check = ("web-server-01", 200, 150)
print(f"Server {check[0]} responded in {check[2]}ms")
This works, but it's brittle. The moment you decide you also need to track the "timestamp" of the check, you're in trouble. If you insert the timestamp at the beginning of the tuple, every single piece of code that references check[0], check[1], and check[2] is now broken. You can't just "add a field" without performing a global search-and-replace on your indices. It's a nightmare to maintain.
Why dictionaries aren't always the answer
Now, you might think, "Why not just use a dictionary?" To be fair, {"hostname": "web-server-01", "status": 200} is much more readable. You get named keys, and adding new fields doesn't break existing logic. But dictionaries come with a cost. They are computationally "heavy" because they carry a lot of overhead to manage their hash tables. If you're processing a list of ten thousand health checks every second, that memory overhead adds up quickly. Plus, you're stuck with that clunky check['hostname'] syntax everywhere.
The middle ground: namedtuple
This is where collections.namedtuple comes in. I like to think of it as a hybrid: it has the memory efficiency and immutability of a tuple, but it allows you to access data using names instead of indices. It's essentially a factory for creating small, lightweight classes.
from collections import namedtuple
# We define the "template" once
HealthCheck = namedtuple('HealthCheck', ['hostname', 'status', 'response_time'])
# Now we create an instance
check = HealthCheck("web-server-01", 200, 150)
# Access by name (readable!)
print(f"Server {check.hostname} responded in {check.response_time}ms")
# But it's still a tuple, so we can still unpack it if we want
host, status, time = check
The beauty here is that the HealthCheck object doesn't have a __dict__ of its own, making it nearly as slim as a regular tuple. If you ever need to add a field, you change the definition in one place. While you can't change the values after creation (because tuples are immutable), that's actually a feature in this context—it ensures your data records don't get accidentally mutated as they pass through your pipeline.
📋 Practical Task
Refactoring the GPS Coordinate Parser
You have been handed a legacy script that parses GPS data from a log file. Currently, it uses raw tuples, making the code very difficult to read and maintain. Your task is to refactor this using namedtuple.
Requirements:
- Define a
namedtuplecalledCoordinatewith the fieldslatitude,longitude, andaltitude. - Convert the existing list of raw tuples into a list of
Coordinateobjects. - Write a function called
summarize_location(coord)that takes aCoordinateobject and returns a string in the format:"Lat: [lat], Lon: [lon], Alt: [alt]m". - Ensure the function uses dot notation (e.g.,
coord.latitude) rather than index-based access.
# Starter data
raw_data = [
(34.0522, -118.2437, 87),
(40.7128, -74.0060, 10),
(51.5074, -0.1278, 35)
]
There are no comments for now.