For Loops Unleashed
range, enumerate, zip, and an introduction to list comprehensions.
OK so we used basic for loops last week — looping through a list, using range(), the accumulator pattern. I feel pretty comfortable with those. But I keep seeing stuff like enumerate() and zip() in examples and I have no idea what they do.
Last week gave you the foundations — iterating over a list and using range(). Now we'll cover the tools that make for loops truly powerful. Think of it this way: last week you learned to drive. This week you're learning the highway.
Let's start with range() in more detail. You used range(5) to count 0 through 4. But range() actually takes up to three arguments:
# range(stop) — 0 to stop-1
for i in range(5):
print(i) # 0, 1, 2, 3, 4
# range(start, stop) — start to stop-1
for i in range(2, 6):
print(i) # 2, 3, 4, 5
# range(start, stop, step) — with a step size
for i in range(0, 10, 3):
print(i) # 0, 3, 6, 9
The step argument lets you count by twos, threes, or even backwards with a negative step:
for i in range(10, 0, -2):
print(i) # 10, 8, 6, 4, 2
Remember when we used range(len(names)) last week to get both the index and the value? That felt clunky. Is there a better way?
Yes — enumerate(). It gives you both the index and the value without the range(len(...)) pattern:
fruits = ["apple", "banana", "cherry"]
# The old way (what we did last week)
for i in range(len(fruits)):
print(i, fruits[i])
# The Pythonic way
for i, fruit in enumerate(fruits):
print(i, fruit)
Both produce the same output, but enumerate() is cleaner and less error-prone. The i, fruit syntax is called tuple unpacking — Python splits each pair into two variables.
That's way nicer. What if I have two lists and need to loop through them at the same time? Like, I have a column of names and a column of scores in my spreadsheet, and I want to process them together.
That's exactly what zip() is for. It pairs up elements from two (or more) lists — just like matching two columns in your spreadsheet:
names = ["Alice", "Bob", "Charlie"]
scores = [92, 85, 67]
for name, score in zip(names, scores):
print(f"{name}: {score}")
# Alice: 92
# Bob: 85
# Charlie: 67
Compare that to the range(len(...)) version:
for i in range(len(names)):
print(f"{names[i]}: {scores[i]}")
zip() is cleaner and you don't need to manage indexes. If the lists have different lengths, zip() stops at the shortest one.
I've heard about list comprehensions. They look like magic one-liners. What are those?
A list comprehension is a one-line way to build a list from a loop. Instead of writing a loop with .append(), you write the whole thing as an expression:
# Traditional loop
squares = []
for x in range(5):
squares.append(x ** 2)
print(squares) # [0, 1, 4, 9, 16]
# List comprehension — same result
squares = [x ** 2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
The pattern is [expression for variable in iterable]. You can also add a filter with if:
scores = [92, 85, 67, 74, 55]
passing = [s for s in scores if s >= 70]
print(passing) # [92, 85, 74]
List comprehensions are one of Python's signature features. They're concise, readable, and faster than the equivalent loop.
OK so enumerate for indexes, zip for parallel lists, and comprehensions for building new lists. Can I combine them?
Absolutely. Here's a real-world example. Say you have names and scores — like two columns in your spreadsheet — and you want a list of strings for students who passed:
names = ["Alice", "Bob", "Charlie"]
scores = [92, 55, 78]
results = [f"{name}: Pass" for name, score in zip(names, scores) if score >= 70]
print(results) # ['Alice: Pass', 'Charlie: Pass']
One line. No temporary variables. No index management. That's the power of Python's loop tools working together. Remember the grade function from last week's if/else lesson? Let's combine it with these new tools.
Practice your skills
Sign up to write and run code in this lesson.
For Loops Unleashed
range, enumerate, zip, and an introduction to list comprehensions.
OK so we used basic for loops last week — looping through a list, using range(), the accumulator pattern. I feel pretty comfortable with those. But I keep seeing stuff like enumerate() and zip() in examples and I have no idea what they do.
Last week gave you the foundations — iterating over a list and using range(). Now we'll cover the tools that make for loops truly powerful. Think of it this way: last week you learned to drive. This week you're learning the highway.
Let's start with range() in more detail. You used range(5) to count 0 through 4. But range() actually takes up to three arguments:
# range(stop) — 0 to stop-1
for i in range(5):
print(i) # 0, 1, 2, 3, 4
# range(start, stop) — start to stop-1
for i in range(2, 6):
print(i) # 2, 3, 4, 5
# range(start, stop, step) — with a step size
for i in range(0, 10, 3):
print(i) # 0, 3, 6, 9
The step argument lets you count by twos, threes, or even backwards with a negative step:
for i in range(10, 0, -2):
print(i) # 10, 8, 6, 4, 2
Remember when we used range(len(names)) last week to get both the index and the value? That felt clunky. Is there a better way?
Yes — enumerate(). It gives you both the index and the value without the range(len(...)) pattern:
fruits = ["apple", "banana", "cherry"]
# The old way (what we did last week)
for i in range(len(fruits)):
print(i, fruits[i])
# The Pythonic way
for i, fruit in enumerate(fruits):
print(i, fruit)
Both produce the same output, but enumerate() is cleaner and less error-prone. The i, fruit syntax is called tuple unpacking — Python splits each pair into two variables.
That's way nicer. What if I have two lists and need to loop through them at the same time? Like, I have a column of names and a column of scores in my spreadsheet, and I want to process them together.
That's exactly what zip() is for. It pairs up elements from two (or more) lists — just like matching two columns in your spreadsheet:
names = ["Alice", "Bob", "Charlie"]
scores = [92, 85, 67]
for name, score in zip(names, scores):
print(f"{name}: {score}")
# Alice: 92
# Bob: 85
# Charlie: 67
Compare that to the range(len(...)) version:
for i in range(len(names)):
print(f"{names[i]}: {scores[i]}")
zip() is cleaner and you don't need to manage indexes. If the lists have different lengths, zip() stops at the shortest one.
I've heard about list comprehensions. They look like magic one-liners. What are those?
A list comprehension is a one-line way to build a list from a loop. Instead of writing a loop with .append(), you write the whole thing as an expression:
# Traditional loop
squares = []
for x in range(5):
squares.append(x ** 2)
print(squares) # [0, 1, 4, 9, 16]
# List comprehension — same result
squares = [x ** 2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
The pattern is [expression for variable in iterable]. You can also add a filter with if:
scores = [92, 85, 67, 74, 55]
passing = [s for s in scores if s >= 70]
print(passing) # [92, 85, 74]
List comprehensions are one of Python's signature features. They're concise, readable, and faster than the equivalent loop.
OK so enumerate for indexes, zip for parallel lists, and comprehensions for building new lists. Can I combine them?
Absolutely. Here's a real-world example. Say you have names and scores — like two columns in your spreadsheet — and you want a list of strings for students who passed:
names = ["Alice", "Bob", "Charlie"]
scores = [92, 55, 78]
results = [f"{name}: Pass" for name, score in zip(names, scores) if score >= 70]
print(results) # ['Alice: Pass', 'Charlie: Pass']
One line. No temporary variables. No index management. That's the power of Python's loop tools working together. Remember the grade function from last week's if/else lesson? Let's combine it with these new tools.
Practice your skills
Sign up to write and run code in this lesson.