Blog Post #132: map and filter vs. Comprehensions: Which is More Pythonic?

In Post #130 and Post #131, we learned about the functional programming tools map() and filter(). You might have noticed that the tasks they accomplish—transforming and selecting items from a list—are very similar to what we can do with the list comprehensions we learned about in Post #120.

This leads to a natural question: which one should you use? Both are valid, but one is generally considered more “Pythonic” than the other. In this post, we’ll compare these two approaches side-by-side and discuss the general consensus in the Python community.

The Showdown: Transformation

Let’s start with a simple transformation task: creating a list of squared numbers from an original list.

Using map()

With map(), we typically pair it with a lambda to define the transformation.

numbers = [1, 2, 3, 4]
squared_map = list(map(lambda x: x**2, numbers))
print(squared_map)

Using a List Comprehension

The list comprehension accomplishes the same thing with what many find to be a more direct syntax.

numbers = [1, 2, 3, 4]
squared_comp = [x**2 for x in numbers]
print(squared_comp)

Analysis: For this simple case, the list comprehension is often considered easier to read. The logic x**2 for x in numbers is all contained in one syntactic unit and doesn’t require thinking about an extra function like lambda.

The Showdown: Filtering

Now, let’s look at a filtering task: creating a list of only the even numbers from an original list.

Using filter()

With filter(), we use a lambda to define the “test” that each item must pass.

numbers = [1, 2, 3, 4, 5, 6]
evens_filter = list(filter(lambda x: x % 2 == 0, numbers))
print(evens_filter)

Using a List Comprehension

The list comprehension adds an if clause at the end to perform the filtering.

numbers = [1, 2, 3, 4, 5, 6]
evens_comp = [x for x in numbers if x % 2 == 0]
print(evens_comp)

Analysis: Again, the comprehension is very readable. The filtering condition is a natural part of the syntax, written right after the for loop component.

The Deciding Factor: Combining Transformation and Filtering

This is where the difference in readability becomes most apparent. Let’s try to create a list containing the squares of only the even numbers.

Using map() and filter() Together

To do this with functional tools, you have to nest them.

numbers = [1, 2, 3, 4, 5, 6]

# This can be hard to read
even_squares = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers)))
print(even_squares)

This works, but it’s confusing. You have to read it from the inside out: “first filter the numbers, then map the squaring function onto the result of the filter.”

Using a List Comprehension

The list comprehension handles this combined logic seamlessly.

numbers = [1, 2, 3, 4, 5, 6]

even_squares_comp = [x**2 for x in numbers if x % 2 == 0]
print(even_squares_comp)

This, by contrast, reads almost like a natural English sentence: “Give me x-squared for each x in numbers, if x is even.” The transformation (x**2) and the filter (if x % 2 == 0) are part of one cohesive and highly readable expression.

The Verdict: Readability Counts

While both approaches are valid, list comprehensions are generally considered more “Pythonic” and are preferred in the Python community for their readability, especially for simple to moderately complex tasks.

The Zen of Python (from Post #113) says, “Readability counts” and “There should be one— and preferably only one —obvious way to do it.” For many Python developers, the list comprehension is that one obvious and readable way. There are cases where map might be used (for example, it can sometimes be slightly faster when applying a complex, pre-existing def function), but as a general rule, start with a list comprehension.

What’s Next?

You now understand the trade-offs between the functional map/filter approach and the more idiomatic comprehension approach. Prioritizing readability will guide you to the right choice in most situations.

We’ve spent a lot of time iterating over a single list at a time. But what if you need to loop through two or more lists simultaneously? In Post #133, we will learn about the incredibly useful built-in function for this task: zip().

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment