Python Comprehensions Are Declarative (And Why That Matters)

Published: (January 5, 2026 at 07:48 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Two ways to square every number in a list

# Version A
squares = []
for num in numbers:
    squares.append(num ** 2)
# Version B
squares = [num ** 2 for num in numbers]

Imperative vs. declarative

Version A tells Python how to build the list:

  1. Create an empty list.
  2. Loop through numbers.
  3. Compute the square.
  4. Append to the list.
  5. Repeat.

Version B tells Python what you want:

“Give me a list of each number’s square.”

When reading code you didn’t write, the declarative version makes the intent immediate, whereas the imperative version requires you to trace the loop logic.

Reliability

Declarative code is harder to mess up. In the imperative version you could:

  • Forget to initialize squares = [].
  • Misspell .append() as .appnd().
  • Append the wrong value.
  • Break the loop prematurely.

The comprehension eliminates these failure modes because the pattern is baked into the syntax.

Ask yourself: “Can I understand this comprehension in one quick read?”

When comprehensions work well

Simple transformations

[x ** 2 for x in numbers if x > 0]

When they become too complex (avoid)

[(x, y) for x in range(10) for y in range(10)
 if x != y and (x + y) % 2 == 0 and x ** 2 + y ** 2]

“This is a list of f(x) values.”

Not:

“This becomes a list through these steps.”

Internalizing this distinction helps you reach for comprehensions naturally—and know when a loop serves you better.

Adapted from the upcoming book Zero to AI Engineer: Python Foundations.

I share excerpts like this on Substack →

Back to Blog

Related posts

Read more »