Python Loops — for, while, and Iterator Patterns

Python BasicsLoopsFree Lesson

Advertisement

Python Loops — for, while, and Iterator Patterns

Loops let you execute a block of code repeatedly. Python provides two primary loop constructs — for and while — along with powerful iteration utilities. This tutorial covers everything from basic syntax to advanced iterator techniques used in production Python code.

Learning Objectives

  • Understand for and while loop syntax and when to use each
  • Master range(), enumerate(), zip(), and other iteration tools
  • Use break, continue, and the else clause effectively
  • Recognize and avoid common loop mistakes
  • Apply accumulator, filter, and transform patterns
  • Write efficient loops that avoid unnecessary computation

The for Loop

The for loop iterates over any iterable — lists, tuples, strings, dicts, sets, ranges, and more. Python's for is a foreach loop: it visits each element in order.

for variable in iterable:
    # do something with variable

Iterating Over Sequences

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)
# apple
# banana
# cherry

coordinates = (10, 20, 30)
for coord in coordinates:
    print(f"Coordinate: {coord}")
# Coordinate: 10
# Coordinate: 20
# Coordinate: 30

The range() Function

range(start, stop, step) generates a sequence of integers. The sequence stops before stop.

# 0 to 4
for i in range(5):
    print(i, end=" ")   # 0 1 2 3 4

# Custom start and stop
for i in range(2, 7):
    print(i, end=" ")   # 2 3 4 5 6

# With step
for i in range(0, 20, 3):
    print(i, end=" ")   # 0 3 6 9 12 15 18

# Counting backwards
for i in range(10, 0, -2):
    print(i, end=" ")   # 10 8 6 4 2

Iterating Over Dictionaries

person = {"name": "Alice", "age": 30, "city": "Portland"}

for key in person:             # keys (default)
    print(key)

for key in person.keys():      # keys explicitly
    print(key)

for value in person.values():  # values
    print(value)

for key, value in person.items():  # key-value pairs
    print(f"{key}: {value}")

Iterating Over Sets and Strings

unique_numbers = {1, 2, 3, 4, 5}
for num in unique_numbers:
    print(num, end=" ")    # order not guaranteed

for char in "Python":
    print(char, end=" ")   # P y t h o n

Nested for Loops

for i in range(3):
    for j in range(3):
        print(f"({i},{j})", end=" ")
    print()
# (0,0) (0,1) (0,2)
# (1,0) (1,1) (1,2)
# (2,0) (2,1) (2,2)

The while Loop

A while loop continues as long as its condition is True. Use it when you do not know in advance how many iterations you need.

while condition:
    # code block — condition must eventually become False

Simple Counter

count = 0
while count < 5:
    print(count, end=" ")
    count += 1
# 0 1 2 3 4

Infinite Loops (When They Are Useful)

Infinite loops are intentional in servers, game loops, and event handlers. Always provide an exit mechanism.

running = True
frame = 0
while running:
    frame += 1
    if frame >= 3:
        running = False
    print(f"Frame {frame}")
# Frame 1
# Frame 2
# Frame 3

The while True Pattern

iteration = 0
max_iterations = 5

while True:
    iteration += 1
    if iteration > max_iterations:
        break
    print(f"Processing item {iteration}")
# Processing item 1 through 5

Sentinel Value Loop

values = [10, 25, 37, 42, 58, 63, 71]
index = 0
while index < len(values) and values[index] < 50:
    print(values[index], end=" ")
    index += 1
# 10 25 37 42

break and continue

break — Exit the Loop Early

break immediately terminates the innermost loop.

numbers = [3, 7, 2, 9, 4, 6, 8]
for num in numbers:
    if num > 5:
        print(f"First number greater than 5: {num}")
        break
# First number greater than 5: 7

continue — Skip to Next Iteration

continue jumps to the next iteration, skipping the rest of the body.

for i in range(10):
    if i % 2 == 0:
        continue
    print(i, end=" ")
# 1 3 5 7 9

Combining break and continue

for i in range(20):
    if i % 3 == 0:
        continue
    if i > 14:
        break
    print(i, end=" ")
# 1 2 4 5 7 8 10 11 13 14

The for-else and while-else

Python loops can have an else clause. It runs only if the loop completes without hitting break. Think of it as "no break occurred," not "condition is false."

Search Pattern

primes = [2, 3, 5, 7, 11, 13, 17]
target = 19

for prime in primes:
    if prime == target:
        print(f"Found {target}!")
        break
else:
    print(f"{target} is not in the list")
# 19 is not in the list
target = 7
for prime in primes:
    if prime == target:
        print(f"Found {target}!")
        break
else:
    print(f"{target} is not in the list")
# Found 7!

Common Misunderstanding

# else runs because loop finished normally (no break)
for i in range(3):
    print(i)
else:
    print("Loop completed without break")
# 0
# 1
# 2
# Loop completed without break

enumerate()

enumerate() adds a counter to any iterable, returning (index, value) tuples.

colors = ["red", "green", "blue"]

for index, color in enumerate(colors):
    print(f"{index}: {color}")
# 0: red
# 1: green
# 2: blue

Custom Start Index

for index, color in enumerate(colors, start=1):
    print(f"{index}: {color}")
# 1: red
# 2: green
# 3: blue

Why Not range(len())?

enumerate() is better because it works with any iterable, avoids off-by-one errors, is more readable, and is slightly faster in CPython. Prefer it over range(len(...)).


zip()

zip() combines multiple iterables into tuples, stopping at the shortest one.

names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
    print(f"{name}: {score}")
# Alice: 85
# Bob: 92
# Charlie: 78

Creating a Dictionary with zip

keys = ["name", "age", "city"]
values = ["Alice", 30, "Portland"]
person = dict(zip(keys, values))
# {'name': 'Alice', 'age': 30, 'city': 'Portland'}

Strict Mode (Python 3.10+)

With strict=True, zip raises ValueError if lengths differ:

names = ["Alice", "Bob", "Charlie"]
scores = [85, 92]
try:
    list(zip(names, scores, strict=True))
except ValueError as e:
    print(f"Error: {e}")
# Error: zip() has arguments with different lengths

itertools.zip_longest

Process all elements, filling missing values:

from itertools import zip_longest
names = ["Alice", "Bob", "Charlie", "Diana"]
scores = [85, 92]
for name, score in zip_longest(names, scores, fillvalue="N/A"):
    print(f"{name}: {score}")
# Alice: 85
# Bob: 92
# Charlie: N/A
# Diana: N/A

Iterating Techniques

Reversed()

Iterate in reverse without modifying the original:

numbers = [1, 2, 3, 4, 5]
for num in reversed(numbers):
    print(num, end=" ")
# 5 4 3 2 1

any() and all() with Generators

numbers = [2, 4, 6, 8, 10]
print(all(n % 2 == 0 for n in numbers))  # True
print(any(n > 7 for n in numbers))       # True
print(any(n < 0 for n in numbers))       # False

Loop Patterns

Accumulator Pattern

Collect results as you iterate:

numbers = [1, 2, 3, 4, 5]
total = 0
for num in numbers:
    total += num
print(f"Sum: {total}")  # Sum: 15

Filter Pattern

Keep only items that match:

scores = [85, 42, 91, 38, 76, 55, 88]
passing = [s for s in scores if s >= 60]
print(passing)  # [85, 91, 76, 88]

Transform Pattern

Convert each element:

celsius = [0, 10, 20, 30, 40]
fahrenheit = [t * 9 / 5 + 32 for t in celsius]
print(fahrenheit)  # [32.0, 50.0, 68.0, 86.0, 104.0]

Find First / Any / All

data = [3, 7, 11, 2, 9, 4]

first_even = None
for num in data:
    if num % 2 == 0:
        first_even = num
        break
print(f"First even: {first_even}")  # First even: 2

all_positive = all(num > 0 for num in data)
print(f"All positive: {all_positive}")  # All positive: True

Dictionary Building in Loops

words = ["apple", "banana", "cherry", "avocado", "blueberry"]
grouped = {}
for word in words:
    letter = word[0]
    if letter not in grouped:
        grouped[letter] = []
    grouped[letter].append(word)
# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}

Nested Loops vs List Comprehensions

# Nested loop
pairs = []
for i in range(4):
    for j in range(i + 1, 4):
        pairs.append((i, j))

# Equivalent comprehension
pairs = [(i, j) for i in range(4) for j in range(i + 1, 4)]
# [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]

# Flattening nested lists
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [val for row in matrix for val in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Performance

for vs while

for loops are faster because they are optimized at the C level. Use for when possible; use while only when the exit condition depends on runtime logic.

import time
n = 1_000_000

start = time.time()
for i in range(n):
    pass
for_time = time.time() - start

start = time.time()
i = 0
while i < n:
    i += 1
while_time = time.time() - start

print(f"for:  {for_time:.4f}s")   # ~0.05s
print(f"while: {while_time:.4f}s") # ~0.08s

Generator Expressions for Memory

import sys

# List — stores everything in memory
squares_list = [x ** 2 for x in range(1_000_000)]

# Generator — yields one at a time
squares_gen = (x ** 2 for x in range(1_000_000))

print(sys.getsizeof(squares_list))  # ~8 MB
print(sys.getsizeof(squares_gen))   # ~200 bytes

Common Mistakes

Infinite while Loops

# Wrong — forgot to update condition
x = 0
# while x < 5:
#     print(x)  # infinite loop!

# Right
x = 0
while x < 5:
    print(x, end=" ")
    x += 1
# 0 1 2 3 4

Modifying a List During Iteration

# Wrong — skips elements
numbers = [1, 2, 3, 4, 5]
# for num in numbers:
#     if num % 2 == 0:
#         numbers.remove(num)

# Right — iterate over a copy
numbers = [1, 2, 3, 4, 5]
for num in numbers[:]:
    if num % 2 == 0:
        numbers.remove(num)
print(numbers)  # [1, 3, 5]

range() Off-by-One

items = ["a", "b", "c", "d"]
# Use zip to iterate pairs instead of index math
for a, b in zip(items, items[1:]):
    print(a, b)
# a b
# b c
# c d

else Clause Confusion

# else runs when loop completes without break
for i in range(5):
    pass
else:
    print("Runs — no break occurred")

for i in range(5):
    if i == 3:
        break
else:
    print("Does NOT print — break occurred")

Not Using enumerate

fruits = ["apple", "banana", "cherry"]

# Not Pythonic
i = 0
for fruit in fruits:
    print(f"{i}: {fruit}")
    i += 1

# Pythonic
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")

Practice Exercises

Exercise 1: Factorial Calculator

Write a loop that computes the factorial of a number (n!) using both for and while.

Solution

def factorial_for(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

def factorial_while(n):
    result = 1
    i = 1
    while i <= n:
        result *= i
        i += 1
    return result

print(factorial_for(5))   # 120
print(factorial_while(5)) # 120

Exercise 2: FizzBuzz

Print 1 through 30. Multiples of 3 → "Fizz". Multiples of 5 → "Buzz". Both → "FizzBuzz".

Solution

for i in range(1, 31):
    if i % 3 == 0 and i % 5 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

Exercise 3: Find Duplicates

Find all duplicate elements in a list using enumerate and a set.

Solution

numbers = [1, 3, 5, 3, 7, 1, 9, 5, 3]
seen = set()
duplicates = set()
for num in numbers:
    if num in seen:
        duplicates.add(num)
    seen.add(num)
print(f"Duplicates: {sorted(duplicates)}")
# Duplicates: [1, 3, 5]

Key Takeaways

ConceptSyntaxWhen to Use
for loopfor x in iter:Known or finite iterations
while loopwhile cond:Unknown iteration count
range()range(start, stop, step)Numeric sequences
enumerate()enumerate(iter, start=0)Need index + value
zip()zip(a, b, ...)Parallel iteration
breakbreakExit loop early
continuecontinueSkip current iteration
elseelse: (after loop)Run if no break occurred
  • Use for when iterating over a known sequence; while when the exit condition depends on runtime logic.
  • enumerate() is almost always better than range(len(...)).
  • zip() pairs elements from multiple iterables — use strict=True to catch length mismatches.
  • The else clause on loops runs when the loop finishes without break.
  • Prefer generator expressions for large datasets to save memory.
  • Never modify a collection while iterating over it — iterate over a copy instead.

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement