Python developers learn list comprehensions early and stop there — missing two more powerful layers. Generator expressions give you the same syntax with O(1) memory. The itertools module gives you C-level performance for the most common iteration patterns. Knowing when to use each is the difference between Python code that works and Python code that scales.
⚡ TL;DR: List comprehension when you need all results at once and size is manageable. Generator expression when data is large or you only need to iterate once. itertools when you need combinations, permutations, grouping, chaining, or sliding windows — always in O(1) memory.
List comprehensions — fast, readable, eager
# Basic: [expression for item in iterable if condition]
squares = [x**2 for x in range(1000) if x % 2 == 0]
# Nested: equivalent to nested for loops
matrix = [[i*j for j in range(5)] for i in range(5)]
# Dict comprehension
word_lengths = {word: len(word) for word in ['hello', 'world']}
# Set comprehension — automatic deduplication
unique_lengths = {len(word) for word in words}
# Benchmark vs for loop (1M elements):
# for loop: 180ms
# list comprehension: 90ms (2x faster — runs in C)
# When to use: need list, size < a few million, transform + filterGenerator expressions — lazy, O(1) memory
# Same syntax as list comp but with () instead of []
# Does NOT compute all values immediately
# Memory comparison on 10M elements:
import sys
list_comp = [x**2 for x in range(10_000_000)] # ~400MB
gen_expr = (x**2 for x in range(10_000_000)) # ~120 bytes!
print(sys.getsizeof(list_comp)) # 89,095,160 bytes
print(sys.getsizeof(gen_expr)) # 120 bytes
# Generators are consumed once
gen = (x**2 for x in range(5))
list(gen) # [0, 1, 4, 9, 16]
list(gen) # [] — exhausted!
# Pipeline: chain generators for O(1) memory throughout
def read_logs(filename):
with open(filename) as f:
for line in f: yield line
errors = (line for line in read_logs('app.log') if 'ERROR' in line)
severe = (line for line in errors if 'CRITICAL' in line)
# Process 100GB log file in O(1) memoryitertools — the missing Python standard library
import itertools
# chain: flatten iterables without creating intermediate list
result = list(itertools.chain([1,2], [3,4], [5,6]))
# [1, 2, 3, 4, 5, 6]
# chain.from_iterable: flatten nested iterable
nested = [[1,2],[3,4],[5,6]]
result = list(itertools.chain.from_iterable(nested)) # [1,2,3,4,5,6]
# islice: take N items from any iterable (like Python slice but lazy)
first_100 = list(itertools.islice(huge_generator(), 100))
# groupby: group consecutive items by key (MUST be sorted first)
data = [('a',1),('a',2),('b',3),('b',4)]
for key, group in itertools.groupby(data, key=lambda x: x[0]):
print(key, list(group)) # a [(a,1),(a,2)], b [(b,3),(b,4)]
# product: cartesian product (nested loops without nesting)
for x, y, z in itertools.product(range(3), repeat=3):
print(x, y, z) # 27 combinations
# combinations and permutations
list(itertools.combinations('ABC', 2)) # [(A,B),(A,C),(B,C)]
list(itertools.permutations('ABC', 2)) # [(A,B),(A,C),(B,A),(B,C),(C,A),(C,B)]
# pairwise: sliding window of 2 (Python 3.10+)
list(itertools.pairwise([1,2,3,4])) # [(1,2),(2,3),(3,4)]
# accumulate: running aggregation
list(itertools.accumulate([1,2,3,4], lambda a,b: a+b)) # [1,3,6,10] running sumPerformance benchmark: list vs generator vs itertools
import timeit, itertools
data = list(range(1_000_000))
# Sum of squares of even numbers
# List comprehension (materializes full list)
def with_list():
return sum([x**2 for x in data if x%2==0])
# Generator (no intermediate list)
def with_gen():
return sum(x**2 for x in data if x%2==0)
# itertools.compress (most explicit, C-level)
def with_itertools():
evens = itertools.compress(data, (x%2==0 for x in data))
return sum(x**2 for x in evens)
# Results:
# list comprehension: 280ms (400MB memory peak)
# generator: 320ms (O(1) memory) — slightly slower, huge memory win
# itertools: 380ms (O(1) memory) — most Pythonic for complex pipelines
# Rule: generator usually wins on memory, similar speed for single-passDecision guide
- ✅ List comprehension: need random access, multiple passes, small-medium data, return value
- ✅ Generator expression: large data, single pass, memory-constrained, pipeline
- ✅ itertools: combinatorics, grouping, chaining, windowing — always C-level performance
- ✅ Generator function (yield): complex stateful iteration logic that's hard to express as expression
- ❌ Never use list comprehension to build a list just to immediately iterate over it once
- ❌ Never nest list comprehensions more than 2 levels — use explicit for loops
These patterns build directly on Python performance optimization — generator pipelines are one of the biggest wins for memory-constrained systems. For the stateful generator pattern, see the JavaScript generators guide — the concepts are identical across languages. External reference: Python itertools documentation.
Free Weekly Newsletter
🚀 Don’t Miss the Next Cheat Code
Related: Python Generators and Yield: Lazy Evaluation for Memory-Efficient Data Processing · Python Decorators Explained: From Simple Wrappers to Production Patterns · Python asyncio vs Threading vs Multiprocessing: When to Use Each
Related: Python Dictionary Methods and Tricks: The Complete Guide · JavaScript Async/Await: Every Pattern, Pitfall, and Performance Trick · Python Dictionary Methods and Tricks: The Complete Guide for 2025
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
