Two Ifs In A Comprehension? Give It A Function Name
If your list comprehension needs a second if, it needs a function name. A comprehension is a great tool for one transform and, at most, one simple filter. The moment you stack two conditions — or a condition plus a nested loop — into a single bracketed line, you've written something the next reader has to mentally un-compress. Name it instead.
Why one line stops being readable
A comprehension packs three things into one expression: what you produce, where it comes from, and what you keep. With one for and one if, the eye parses it in a single pass. Add a second if, a for clause, or a ternary inside the output expression, and the reader now juggles 4–5 moving parts with zero named intermediate steps.
The style guides are blunt about this. Google's Python style guide (section 2.7) allows comprehensions but rules that "multiple for clauses or filter expressions are not permitted — optimize for readability, not conciseness." PEP 8's core principle is the same: readability counts, and clever compressed one-liners are discouraged because code is read far more often than it is written. Even the official Python tutorial, right after showing a nested comprehension, tells you that "in the real world, you should prefer built-in functions to complex flow statements."
The fix: expand into a named generator function
Take a line like this:
active_admins = [u.email for u in users
if u.is_active if u.role == "admin"]
Expand it into a generator function whose name states the intent:
def active_admin_emails(users):
for user in users:
if not user.is_active:
continue
if user.role != "admin":
continue
yield user.email
active_admins = list(active_admin_emails(users))
Three things just happened:
- The logic got a name.
active_admin_emailsdocuments the intent at every call site — no comment needed. - It became testable. You can unit-test the function directly with three tiny fixtures: an inactive admin, an active non-admin, an active admin. The inline comprehension could only be tested through whatever surrounded it.
- It stayed lazy. A generator function yields items one at a time, exactly like the comprehension's cousin, the generator expression — so you lose nothing on memory. Call
list()only when you actually need a list.
Rules of thumb
| Shape | Verdict |
|---|---|
One for, no if | Comprehension — ideal |
One for, one simple if | Comprehension — still fine |
Two if clauses (or if + ternary) | Named generator function |
Two for clauses (nested loops) | Named function or explicit loops |
| Any comprehension you had to line-break twice | Named function |
The trigger is mechanical on purpose: "second if → function name" is a rule you never have to argue about in review.
Why this matters more with a coding agent
Coding agents imitate the code around them. If your codebase is full of dense multi-clause comprehensions, the agent learns that nesting logic into one line is house style — and it will happily generate four-clause monsters you then have to review character by character. Seed the repo with named generator functions and the agent copies that pattern instead: small, named, individually testable units it can also modify safely, because each condition lives on its own line with its own diff.
Power-user notes
yieldis banned inside comprehensions anyway. Since Python 3.8,yieldandyield fromare illegal inside comprehensions and generator expressions — so the moment logic needs to yield, a named generator function is not just cleaner, it's the only option.- Merge conditions when they're one idea.
if u.is_active and u.role == "admin"is one predicate, not two clauses. If the combined predicate still reads as a single concept, extract it into a function (is_active_admin(u)) and keep the comprehension. - Prefer built-ins over cleverness. The tutorial's transpose example replaces a nested comprehension with
list(zip(*matrix)). Before naming a function, check whether a built-in already says it better.
Resources
- Google Python Style Guide §2.7 — Comprehensions & Generator Expressions
- Python tutorial — List Comprehensions (and nested comprehensions)
- PEP 8 — Style Guide for Python Code
- Python language reference — Generator expressions and yield
- PEP 202 — List Comprehensions
Watch the reel, then go further. Yeda AI Tips is a short-form series on AI-assisted coding — one concrete tip per minute.