Sequential Programs in Python
Learn to write clean, readable pipelines using comprehensions, map, filter, and functional patterns. Transform nested loops into elegant sequential programs.
A sequential program is a piece of code that takes a value, transforms it in a step-by-step manner, and returns a final result. In Python, we call these transformations pipelines or chains.
The most natural way to write sequential programs is through nested for loops. But nested loops have problems: they're hard to read, they require mutable state, and they tangle data transformation with side effects. In this guide, we'll explore a better way using functional programming patterns that Python makes easy.
"Inside every large program is a small program struggling to get out.": Tony Hoare
What you'll learn
- How to write sequential programs using list comprehensions
- The difference between
map,filter, andflatMap - How list comprehensions translate to function chains
- When to use comprehensions vs chained methods
- How to handle nested transformations elegantly
- Real-world patterns for processing data pipelines
The Problem: Nested Loops
Let's say we have a list of books with their authors, and we want to count how many have "Python" in the title:
books = [
{"title": "FP in Python", "authors": ["Chiusano", "Bjarnason"]},
{"title": "The Hobbit", "authors": ["Tolkien"]},
{"title": "Modern Python", "authors": ["Urma", "Fusco"]}
]
# Using a for loop
titles = []
for book in books:
titles.append(book["title"])
count = 0
for title in titles:
if "Python" in title:
count += 1
print(count) # Output: 22
This works, but notice what we're doing: we're mutating a list, iterating twice, and mixing data transformation with logic. Let's make this more elegant.
Building Pipelines with map() and filter()
Python has two fundamental functions for building pipelines: map() applies a function to every element, and filter() keeps only elements that satisfy a condition.
books = [
{"title": "FP in Python", "authors": ["Chiusano", "Bjarnason"]},
{"title": "The Hobbit", "authors": ["Tolkien"]},
{"title": "Modern Python", "authors": ["Urma", "Fusco"]}
]
# As a pipeline
titles = map(lambda book: book["title"], books)
python_books = filter(lambda title: "Python" in title, titles)
count = len(list(python_books))
print(count) # Output: 22
Each step of the pipeline has an input and output. The output type of one step must match the input type of the next. This creates a chain of transformations.
Click through to see how data flows through each transformation:
List Comprehensions: The Pythonic Way
Python gives us a more readable syntax for pipelines called list comprehensions. They look similar to set notation from mathematics and express intent more clearly than nested function calls.
# List comprehension version
count = len([title for book in books
for title in [book["title"]]
if "Python" in title])
print(count) # Output: 2
# Even simpler
python_titles = [book["title"] for book in books
if "Python" in book["title"]]
count = len(python_titles)
print(count) # Output: 22
List comprehensions are equivalent to the chained map() and filter() calls, but they read like English: "for each book in books, if the title contains 'Python', extract the title."
Handling Nested Data with flatMap()
Now let's solve a harder problem. We have books with multiple authors, and we want a flat list of all authors:
books = [
{"title": "FP in Python", "authors": ["Chiusano", "Bjarnason"]},
{"title": "The Hobbit", "authors": ["Tolkien"]}
]
# Wrong: map gives us list of lists
result = list(map(lambda book: book["authors"], books))
print(result)
# [["Chiusano", "Bjarnason"], ["Tolkien"]]
# Right: use list comprehension to flatten
all_authors = [author for book in books
for author in book["authors"]]
print(all_authors)
# ["Chiusano", "Bjarnason", "Tolkien"]['Chiusano', 'Bjarnason', 'Tolkien']
When you have a function that returns a list, and you want to flatten the results, you need flatMap (or in Python, the inner loop in a comprehension). This is one of the most important patterns in functional programming.
See the difference between map (nested) and flatMap (flattened):
Real Example: Movie Recommendations
Let's build a more complex pipeline. We have books with authors, and a function that returns movie adaptations for each author. We want to generate recommendation strings.
books = [
{"title": "FP in Python", "authors": ["Chiusano", "Bjarnason"]},
{"title": "The Hobbit", "authors": ["Tolkien"]}
]
def book_adaptations(author):
if author == "Tolkien":
return [
{"title": "An Unexpected Journey"},
{"title": "The Desolation of Smaug"}
]
return []
# Step-by-step pipeline
recommendations = []
for book in books:
for author in book["authors"]:
for movie in book_adaptations(author):
rec = f'You may like {movie["title"]}, because you liked {author}'s {book["title"]}'
recommendations.append(rec)
for rec in recommendations:
print(rec)You may like An Unexpected Journey, because you liked Tolkien's The Hobbit You may like The Desolation of Smaug, because you liked Tolkien's The Hobbit
1. Mutable state (appending to a list)
2. Multiple levels of nesting make it hard to read
3. The loop body mixes data transformation with side effects
We can solve this with a list comprehension:
# List comprehension version
recommendations = [
f'You may like {movie["title"]}, because you liked {author}'s {book["title"]}'
for book in books
for author in book["authors"]
for movie in book_adaptations(author)
]
for rec in recommendations:
print(rec)You may like An Unexpected Journey, because you liked Tolkien's The Hobbit You may like The Desolation of Smaug, because you liked Tolkien's The Hobbit
The comprehension reads from left to right, top to bottom:
- For each
bookinbooks - For each
authorinbook["authors"] - For each
movieinbook_adaptations(author) - Create a recommendation string using all three variables
This is declarative (what we want, not how to get it) and immutable (no intermediate state).
Filtering Inside Comprehensions
We can add conditions to filter at any level:
# Only include movies from authors whose name starts with 'T'
recommendations = [
f'You may like {movie["title"]}, because you liked {author}'s {book["title"]}'
for book in books
for author in book["authors"]
if author.startswith('T') # Add a condition here
for movie in book_adaptations(author)
if "Unexpected" in movie["title"] # And here
]
for rec in recommendations:
print(rec)You may like An Unexpected Journey, because you liked Tolkien's The Hobbit
The if clause filters at that level of the comprehension. This is cleaner than wrapping each loop with a conditional.
When to Use Comprehensions vs Methods
Key Takeaways
- Sequential programs transform data through a pipeline of steps, where each step's output feeds into the next step's input.
- List comprehensions are Python's native way to express these pipelines. They combine map, filter, and flattening into one readable expression.
- Immutability matters. Avoid mutating intermediate lists. Instead, build the final result in one expression.
- Multiple loops become one comprehension. The order of
forclauses matters—inner loops become subsequentforclauses. - Conditions filter at each level. Add
ifclauses to filter data without nesting everything in conditionals. - Readability is the goal. If a comprehension gets too complex, break it into smaller pieces or use function chains with descriptive function names.
Practice: Book Recommendations Expanded
Try writing a comprehension to:
- Extract all unique authors from the books list
- Find all movies with more than 10 characters in the title
- Group recommendations by author (using a comprehension to build tuples)
- Create a dict mapping authors to their movies
# Solution: Unique authors
unique_authors = list(set(
author
for book in books
for author in book["authors"]
))
# Solution: Filter by movie title length
long_movie_titles = [
movie["title"]
for book in books
for author in book["authors"]
for movie in book_adaptations(author)
if len(movie["title"]) > 10
]
# Solution: Group by author
by_author = {
author: [
movie["title"]
for movie in book_adaptations(author)
]
for author in unique_authors
}
print(by_author){'Chiusano': [], 'Bjarnason': [], 'Tolkien': ['An Unexpected Journey', 'The Desolation of Smaug']}The key insight is that comprehensions can express complex data transformations in a declarative way. Once you understand the order of for and if clauses, you can express almost any sequential transformation.