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
58: Nested Comprehensions
I've seen this happen to almost every developer I've mentored: they try to write their first nested list comprehension, and they instinctively try to "nest" the syntax by putting the innermost loop last. It feels intuitive, like you're wrapping layers around the result. But in Python, that's a one-way ticket to a NameError.
The "Inside-Out" Order Trap
If you're trying to flatten a matrix (a list of lists) into a single list, your instinct might be to write it like this:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# This will crash!
flat = [item for item in row for row in matrix]
If you run this, Python will scream at you: NameError: name 'row' is not defined. Why? Because Python reads comprehension clauses from left to right. In the example above, you're telling Python to iterate over item in row before you've even told it what row is. You're trying to use a variable before it's been created by the outer loop.
Reading Left-to-Right, Top-to-Bottom
The secret to mastering nested comprehensions is simple: the order of the for clauses is exactly the same as the order they would appear in a standard indented for loop. I always tell my students to write the loop out normally first, then just strip away the indentation and the append() call.
Let's look at the same matrix flattening, but written as a standard loop:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = []
for row in matrix: # Outer loop
for item in row: # Inner loop
flat.append(item) # Result
Now, just read those lines from top to bottom and put them right after your result variable. That's your comprehension:
flat = [item for row in matrix for item in row]
It feels weird at first because the "result" (item) comes first, but the sequence of the loops stays linear. for row in matrix happens first, then for item in row happens second.
Nested Expressions vs. Nested Clauses
Here is where things get slightly confusing. There is a big difference between a nested clause (what we just did to flatten a list) and a nested expression (creating a list of lists).
If you want to keep the structure of your matrix but modify every element—say, squaring every number—you aren't flattening it. You're putting a comprehension inside another comprehension. This is a nested expression:
matrix = [[1, 2, 3], [4, 5, 6]]
# A list of lists: the inner comprehension is the "expression"
squared_matrix = [[item**2 for item in row] for row in matrix]
# Result: [[1, 4, 9], [16, 25, 36]]
Notice the brackets. The inner [...] creates a new list for every single row in the outer loop. If you see double brackets at the start, you're building a nested structure. If you see a single set of brackets with multiple for keywords, you're flattening a structure. I personally find the latter harder to read once you get beyond two levels, so if you find yourself writing three or four nested for clauses, just do yourself a favor and use a regular loop. Your future self (and your teammates) will thank you.
📋 Practical Task
Flattening a Filtered Coordinate Grid
You are working on a game map represented as a 2D grid of strings. Some cells are "walkable" (marked as ".") and some are "walls" (marked as "#"). Your goal is to generate a single, flat list of coordinates (row_index, col_index) for every walkable cell in the map.
The Map:
game_map = [
[".", "#", "."],
["#", ".", "#"],
[".", "#", "."]
]
Your Task: Write a single nested list comprehension that iterates through the game_map using enumerate() to keep track of the indices, and produces a flat list of tuples for only the walkable "." cells.
Expected Output: [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)]
There are no comments for now.