For Loops and the range Function in Python
A practical guide to Python for loops — iterating over sequences, the range function, enumerate and zip, nested loops, and the idiomatic patterns you will use every day.
What you'll learn
- ✓How for loops iterate over any iterable
- ✓Every form of the range function
- ✓When to use enumerate, zip, and reversed
- ✓How nested loops work and when to flatten them
- ✓The else clause on a for loop — yes, it exists
Prerequisites
- •Comfortable with lists — see Lists
- •Comfortable with conditionals — see Conditionals
The Python for loop is one of the cleanest iteration constructs in any language. It does not count an index for you. It does not require you to manage a length. It simply walks through an iterable — a list, a string, a file, a generator, a range — and gives you each value in turn. Learn the small set of helper functions that go with it and you can express almost any iteration clearly.
The basic for loop
A for loop takes the form for <name> in <iterable>:. On each iteration, <name> is bound to the next value:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
That is the whole syntax. Whatever appears after in only needs to be iterable — meaning Python can request values from it one at a time. Lists, tuples, strings, sets, dictionaries, files, and generators are all iterable.
for letter in "hello":
print(letter)
# h e l l o (each on its own line)
Iterating a dictionary gives you keys by default; use .items() for key-value pairs:
prices = {"apple": 1.20, "banana": 0.50}
for name, price in prices.items():
print(f"{name}: ${price:.2f}")
The range function
range produces a sequence of integers without building a list in memory. It has three forms:
range(stop) # 0, 1, ..., stop - 1
range(start, stop) # start, start + 1, ..., stop - 1
range(start, stop, step) # start, start + step, ... (excludes stop)
Examples:
for i in range(5):
print(i)
# 0 1 2 3 4
for i in range(2, 6):
print(i)
# 2 3 4 5
for i in range(0, 10, 2):
print(i)
# 0 2 4 6 8
for i in range(10, 0, -1):
print(i)
# 10 9 8 7 6 5 4 3 2 1
Note the exclusive upper bound — range(5) stops at 4. This matches Python’s slicing semantics and trips beginners up exactly once.
You rarely need list(range(...)). The loop works on the range object directly, and that is more memory-efficient.
Iterate over values, not indices
A common mistake from other languages is to write:
fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
print(fruits[i])
This works, but it is not idiomatic. Iterate directly:
for fruit in fruits:
print(fruit)
If you genuinely need both the index and the value, use enumerate:
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 apple
# 1 banana
# 2 cherry
enumerate takes a start argument when you want one-based indices for human-facing output:
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
# 1. apple
# 2. banana
# 3. cherry
Iterate two sequences in parallel with zip
When you have two (or more) lists of related data, zip pairs them up:
names = ["Alice", "Bob", "Carol"]
ages = [30, 25, 35]
for name, age in zip(names, ages):
print(f"{name} is {age}")
zip stops at the shortest sequence. If you need to know that lengths matched, pass strict=True (Python 3.10+) — it raises ValueError on mismatch:
for n, a in zip(names, ages, strict=True):
...
zip is the right answer almost every time you would otherwise reach for range(len(...)).
reversed and sorted
To iterate backwards, wrap the iterable with reversed:
for n in reversed(range(5)):
print(n)
# 4 3 2 1 0
To iterate in sorted order without mutating the original, use sorted:
scores = [82, 47, 91, 56, 73]
for score in sorted(scores):
print(score)
Both return new iterables — the originals are untouched. See Python Lists for how sorted differs from the in-place .sort() method.
Try it yourself. Use range and enumerate to print a multiplication table for 7 from 1 to 10, formatted like 1 x 7 = 7. Then print the same table in reverse using reversed.
Loop body essentials: break, continue, pass
Three keywords control flow inside a loop:
breakexits the loop immediatelycontinueskips to the next iterationpassdoes nothing (a placeholder when syntax requires a statement)
# Find the first negative number
numbers = [3, 7, -2, 9, -5]
for n in numbers:
if n < 0:
print("First negative:", n)
break
# First negative: -2
# Skip empty lines
lines = ["hello", "", "world", "", "!"]
for line in lines:
if not line:
continue
print(line)
# hello
# world
# !
We will see break and continue again in the while loops post.
The for ... else clause
Python for loops have an optional else clause that runs when the loop completes without hitting a break:
def find_first_negative(numbers):
for n in numbers:
if n < 0:
print("Found:", n)
break
else:
print("No negatives.")
find_first_negative([1, 2, 3]) # No negatives.
find_first_negative([1, -2, 3]) # Found: -2
It is genuinely useful for searches, but rare enough that many readers do not know it exists. Use it when it improves clarity and add a brief comment.
Nested loops
A loop inside a loop iterates the inner sequence once per outer step:
for row in range(1, 4):
for col in range(1, 4):
print(f"({row},{col})", end=" ")
print()
# (1,1) (1,2) (1,3)
# (2,1) (2,2) (2,3)
# (3,1) (3,2) (3,3)
Nested loops are unavoidable for 2D data, but flatten where you can. Two flattening techniques:
itertools.product turns nested loops into a single one when you only care about the combination:
from itertools import product
for row, col in product(range(1, 4), range(1, 4)):
print(f"({row},{col})", end=" ")
Comprehensions combine iteration and construction:
pairs = [(r, c) for r in range(1, 4) for c in range(1, 4)]
Modifying lists while iterating
Do not mutate a list as you iterate it — Python’s iteration position is based on indices, so deletions shift everything underneath:
nums = [1, 2, 3, 4, 5]
for n in nums:
if n % 2 == 0:
nums.remove(n) # buggy — may skip elements
Build a new list instead:
nums = [1, 2, 3, 4, 5]
nums = [n for n in nums if n % 2 != 0]
print(nums) # [1, 3, 5]
This is one of those issues that bites everyone exactly once. Once you have seen it, you will reach for a comprehension or filter automatically.
Try it yourself. Given grid = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], write a nested loop that computes the sum of all cells. Then rewrite it as a single expression using sum and a generator expression.
A worked example
Below is a small program that reads a list of order records and prints a summary by customer. It uses for, enumerate, dictionary iteration, and an early continue.
orders = [
{"customer": "Alice", "amount": 49.99, "status": "paid"},
{"customer": "Bob", "amount": 15.00, "status": "pending"},
{"customer": "Alice", "amount": 12.50, "status": "paid"},
{"customer": "Carol", "amount": 30.00, "status": "refunded"},
{"customer": "Bob", "amount": 22.00, "status": "paid"},
]
totals = {}
for order in orders:
if order["status"] != "paid":
continue
name = order["customer"]
totals[name] = totals.get(name, 0.0) + order["amount"]
print("Paid totals by customer:")
for i, (name, total) in enumerate(sorted(totals.items()), start=1):
print(f" {i}. {name}: ${total:.2f}")
Output:
Paid totals by customer:
1. Alice: $62.49
2. Bob: $22.00
Every element of the loop — iteration, filtering, accumulation, and ordered output — is something you will reuse in real code.
Recap
You now know:
foriterates over any iterable, no index management requiredrange(start, stop, step)produces integer sequences cheaply- Prefer
enumerateoverrange(len(...))when you need indices zipwalks multiple sequences in parallel; usestrict=Trueto catch length mismatchesbreak,continue, and the rarefor ... elseround out the syntax- Flatten nested loops with
itertools.productor comprehensions when natural - Never mutate a list while iterating it — build a new one
Next steps
for covers most iteration, but sometimes you do not know how many iterations you need in advance. The next post covers while loops, the break/continue pair in more depth, and how to write loops that terminate safely.
→ Next: While Loops, break, and continue in Python
Questions or feedback? Email codeloomdevv@gmail.com.