In our last few posts, we’ve celebrated comprehensions as a concise, powerful, and “Pythonic” way to create lists, sets, and dictionaries. It can be tempting to see them as a superior replacement for every for
loop.
However, the most important principle of Pythonic code is readability. Sometimes, a comprehension can be too clever, becoming so dense that it’s difficult to understand. In these cases, a traditional for
loop is the better, more Pythonic choice.
This post will provide practical advice on when to resist the urge to write a complex comprehension and stick with a clear, multi-line for
loop instead.
The Golden Rule: “Readability Counts”
Let’s revisit The Zen of Python from Post #113. Two of its most important lines are “Readability counts” and “Simple is better than complex.” This is our guiding principle.
A comprehension is only “Pythonic” if it makes the code easier to understand. If it makes it harder, it has failed, and you should use a for
loop instead. A readable for
loop is always more Pythonic than an unreadable comprehension.
Red Flags: When a Comprehension Might Be Too Complex
Here are a few signs that your list comprehension might be doing too much:
- It’s too long: If the line is so long that you have to scroll horizontally to read it, it’s a strong sign it should be a
for
loop. Code should be easy to read at a glance. - It has nested logic: Comprehensions can contain nested loops (multiple
for
clauses) and multipleif
conditions. While possible, this is often a recipe for unreadable code. - You need to do more than just create a list: Remember, a comprehension’s only job is to create a new collection. If you need to print messages, update counters, handle errors, or perform other actions inside the loop, you must use a standard
for
loop.
A Practical Example: Refactoring a Complex Comprehension
Let’s look at a case where a comprehension is technically possible, but a for
loop is much clearer.
Our task: From a list of user dictionaries, we want to get the names of all users who are 18 or older and live in “New York”.
The Complex Comprehension
You could write this as a single, long list comprehension.
people = [
{'name': 'Alice', 'age': 25, 'location': 'New York'},
{'name': 'Bob', 'age': 17, 'location': 'New York'},
{'name': 'Charlie', 'age': 30, 'location': 'Boston'},
]
# This works, but it's dense and hard to read quickly.
adult_ny_residents = [person['name'] for person in people if person['age'] >= 18 and person['location'] == 'New York']
print(adult_ny_residents)
This works, but you have to read it very carefully to parse all the logic crammed into one line.
The Clearer for
Loop
Now let’s write the same logic as a standard for
loop.
adult_ny_residents = []
for person in people:
is_adult = person['age'] >= 18
is_in_ny = person['location'] == 'New York'
if is_adult and is_in_ny:
adult_ny_residents.append(person['name'])
print(adult_ny_residents)
This version is longer, but it’s significantly more readable. By breaking the logic into separate lines and using descriptive variable names (is_adult
, is_in_ny
), the intent of the code is immediately obvious. It’s also much easier to debug, as you could add a print()
statement inside the loop to inspect the variables.
What’s Next?
Comprehensions are a fantastic tool, but they are not a replacement for every for
loop. Use them for simple transformations and filters where the logic is clear and concise. When your logic becomes more complex, prioritize clarity and fall back on a well-written, multi-line for
loop.
We’ve been creating new lists in memory with both for
loops and comprehensions. This works great for reasonably sized collections, but what happens when you need to process a list with millions, or even billions, of items? Storing it all in memory can be slow or even impossible. In Post #125, we will explore this memory problem and set the stage for a more memory-efficient solution.
Author

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