List Comprehensions
The Assembly Line
Imagine a factory assembly line. Raw parts come in on a conveyor belt, each part gets transformed by a machine, and the finished items drop into a box at the end. Some factories also have an inspector who checks each part before it reaches the machine -- parts that fail the check get tossed out.
A list comprehension works the same way:
- Conveyor belt -- something feeds in the raw values (a
range(), a list, a string, or even a generator). - Machine -- an expression transforms each value.
- Inspector (optional) -- a condition decides which values get through.
- Box -- the result is a brand-new list.
Basic Syntax
This reads almost like English: "give me expression for each
variable in iterable". The iterable can be a range(), a
list, a string, or a generator.
Here the "machine" just passes each value through unchanged.
Transforming Values
Put any expression before for to transform each value:
Adding a Filter
Add if condition after the iterable to keep only values that pass the
test:
Combine transformation and filtering:
Practical Examples
Even numbers
Countdown
Using range with two or three arguments
All three range() forms work inside comprehensions:
print([x for x in range(2, 5)]) # prints: [2, 3, 4]
print([x for x in range(0, 10, 3)]) # prints: [0, 3, 6, 9]
Comprehension vs. For Loop
A list comprehension is a short way to write a common pattern. These two snippets do the same thing:
For loop:
let result = []
for x in range(5) {
if x > 2 {
result.push(x * x)
}
}
print(result) # prints: [9, 16, 25]
Comprehension:
The comprehension packs the same idea into a single line.
Comprehensions with Other Iterables
The examples above all use range(), but comprehensions work with any
iterable -- lists, strings, and generators:
let doubled = [x * 2 for x in [1, 2, 3]]
print(doubled) # prints: [2, 4, 6]
let chars = [ch for ch in "hello"]
print(chars) # prints: [h, e, l, l, o]
let evens = [x for x in [1, 2, 3, 4, 5, 6] if x % 2 == 0]
print(evens) # prints: [2, 4, 6]
See Iterators & Generators for more on generators and iteration.
Rules
- The iterable can be a
range()call, a list, a string, or a generator. - The loop variable is scoped to the comprehension -- it does not leak into the surrounding code.
- The result is always a brand-new list.
- You can use comprehensions anywhere an expression is allowed --
inside
print(), as a function argument, assigned to a variable, etc.
How It Works Under the Hood
When the compiler sees [x * 2 for x in range(5)], it emits
roughly this sequence:
BUILD_LIST 0-- create an empty list.- Store the list in a hidden variable (like
$comp_0). - Set up the loop (same way
forloops work). - For each iteration:
- If there's a filter, check the condition. Skip this iteration if it's false.
- Evaluate the mapping expression.
LIST_APPEND "$comp_0"-- pop the value and append it to the hidden list.
- After the loop, load
$comp_0back onto the stack.
The LIST_APPEND instruction is the only new opcode. Everything else
reuses the existing for-loop machinery.
Summary
| Part | Example | What it does |
|---|---|---|
| Mapping expression | x * 2 |
Transform each value |
for var in iterable |
for x in range(5) |
Produce raw values |
if condition |
if x > 2 |
Keep only matching values |
| Result | [...] |
A new list of transformed items |