Iteration
Loop over iterables, pair and transform data, build comprehensions, and sort by keys.
Iteration processes one item at a time. Python's for loop asks an iterable for its items,
so code usually loops over values directly instead of manually managing indices.
Direct iteration
total = 0
for price in [2.5, 4.0, 1.5]:
total += price
print(total) # 8.0Strings, lists, tuples, dictionaries, sets, ranges, files, and many library objects are iterable.
Use range for a sequence of integers:
for number in range(2, 10, 2):
print(number) # 2, 4, 6, 8The stop value is excluded. range(5) produces 0 through 4.
enumerate: value plus position
Use enumerate when both index and value matter:
languages = ["Python", "Rust", "Go"]
for position, language in enumerate(languages, start=1):
print(f"{position}. {language}")Prefer this to range(len(languages)); it is direct and less error-prone.
zip: parallel iteration
zip combines iterables position by position:
names = ["Ada", "Grace", "Guido"]
scores = [98, 95, 91]
for name, score in zip(names, scores, strict=True):
print(f"{name}: {score}")By default, zip stops at the shortest iterable, which can silently hide mismatched data.
Python 3.10+ supports strict=True, which raises ValueError when lengths differ. Use it when
equal lengths are an invariant.
Create a dictionary from paired data:
score_by_name = dict(zip(names, scores, strict=True))while loops
Use while when repetition depends on a condition rather than a known iterable:
attempts = 3
while attempts > 0:
print(f"{attempts} attempts remaining")
attempts -= 1Ensure something in the loop can make the condition false.
Controlling a loop
numbers = [3, -1, 0, 7]
for number in numbers:
if number < 0:
continue
if number == 0:
break
print(number)continuestarts the next iteration.breakexits the nearest loop.passdoes nothing; it is a syntactic placeholder, not “continue.”
A loop's else runs only if no break occurred:
target = 7
for number in [2, 4, 6]:
if number == target:
print("Found")
break
else:
print("Not found")Use this sparingly; a helper function returning early may be clearer.
Comprehensions
Comprehensions create containers from iterables:
squares = [number ** 2 for number in range(6)]
even_squares = [number ** 2 for number in range(10) if number % 2 == 0]
lengths = {word: len(word) for word in ["loop", "python"]}
initials = {name[0] for name in ["Ada", "Alan", "Grace"]}Use a comprehension for one readable expression and optional simple filter. Use a regular loop for several transformations, side effects, nested complexity, or error handling.
map and filter
map(function, iterable) lazily transforms items. filter(function, iterable) lazily retains
items for which the function is truthy:
raw_numbers = ["2", "5", "8"]
numbers = list(map(int, raw_numbers))
evens = list(filter(lambda number: number % 2 == 0, numbers))
print(numbers) # [2, 5, 8]
print(evens) # [2, 8]They return iterators, so wrap them in list only when a list is actually needed.
Choose based on clarity:
numbers = [int(value) for value in raw_numbers]
evens = [number for number in numbers if number % 2 == 0]Comprehensions are often clearer for inline Python expressions. map is concise when applying
an existing named function such as int or str.strip. filter can be useful in functional
pipelines, but a comprehension shows both item and condition together.
Iterators are consumed
An iterator produces each item once:
doubled = map(lambda number: number * 2, [1, 2, 3])
print(list(doubled)) # [2, 4, 6]
print(list(doubled)) # []Create it again or materialize it once if multiple passes are required.
Sorting by a key
people = [
{"name": "Grace", "age": 37},
{"name": "Ada", "age": 36},
{"name": "Guido", "age": 67},
]
by_age = sorted(people, key=lambda person: person["age"])
by_name_desc = sorted(
people,
key=lambda person: person["name"].casefold(),
reverse=True,
)The key function runs once per item and returns the comparison key. For common operations,
named functions from operator, such as itemgetter, can replace a lambda.
Sort by multiple criteria with a tuple key:
records = [("Ada", 2), ("Grace", 1), ("Ada", 1)]
print(sorted(records, key=lambda record: (record[0], record[1])))Common mistakes
- Iterating over indices when direct iteration or
enumerateis clearer. - Forgetting that
rangeexcludes its stop. - Allowing
zipto silently truncate when equal lengths are required. - Modifying a collection's size while iterating over it.
- Creating an infinite
whileloop by never changing its condition. - Reusing an exhausted iterator.
- Packing too much logic into a comprehension or lambda.
Decision guidance
- Use
forfor iterable data andwhilefor condition-controlled repetition. - Use
enumeratefor index plus value andzip(..., strict=True)for aligned datasets. - Use a comprehension for a small transform/filter that creates a container.
- Use
mapwhen applying an existing function reads naturally; usefilteronly when it is clearer than a comprehension. - Use
sortedto preserve input and.sort()to intentionally mutate a list.
Practice
- Number a list of tasks starting at one with
enumerate. - Pair products and prices with strict
zip, then create a dictionary. - Produce squares of odd numbers from 1 through 19 with a comprehension.
- Sort
(name, score)tuples by descending score, then by case-insensitive name.
LEARNING RECORD
Finish this lesson
Mark it complete when you can explain the main decision without looking.
KNOWLEDGE CHECK