Python Loops & Iteration
A loop runs a block of code repeatedly. Python gives you two loop statements, for and while, plus a set of helpers (range, enumerate, zip) and expressions (comprehensions, map, filter, lambda) that make iteration concise.
At a Glance
Section titled “At a Glance”| Tool | Use it to | Example |
|---|---|---|
for | Visit every item of an iterable | for x in items: |
while | Repeat until a condition becomes false | while count > 0: |
break | Exit the loop immediately | if found: break |
continue | Skip to the next iteration | if skip: continue |
for ... else | Run code when the loop finished without break | Search patterns |
range() | Generate a sequence of integers | range(1, 5) gives 1, 2, 3, 4 |
enumerate() | Get the index and the item together | for i, x in enumerate(items): |
zip() | Walk several iterables in parallel | for a, b in zip(xs, ys): |
| Comprehension | Build a list from an iterable | [n * 2 for n in nums] |
map() / filter() | Transform or select items | list(map(str, [1, 2])) |
lambda | Write a tiny inline function | lambda x: x * 2 |
for Loops
Section titled “for Loops”A for loop visits each item of an iterable: a list, tuple, string, dictionary, set, range, file, and so on.
programming_languages = ['Rust', 'Java', 'Python', 'C++']
for language in programming_languages: print(language)
for char in 'code': print(char) # c, o, d, eLooping Over Dictionaries
Section titled “Looping Over Dictionaries”By default, a dictionary loop yields the keys. Use .items() to get keys and values together.
ages = {'Ann': 31, 'Bob': 25}
for name in ages: # Keys print(name)
for age in ages.values(): # Values print(age)
for name, age in ages.items(): # Both, unpacked from tuples print(name, age)Nested Loops
Section titled “Nested Loops”An inner loop runs completely for every iteration of the outer loop. With N outer and M inner items, the body executes N * M times.
categories = ['Fruit', 'Vegetable']foods = ['Apple', 'Carrot', 'Banana']
for category in categories: for food in foods: print(category, food) # 6 lines in totalCommon Loop Patterns
Section titled “Common Loop Patterns”# Accumulator: build up a totaltotal = 0for n in [5, 10, 15, 20]: total += nprint(total) # 50
# Counter: tally items that match a conditionvowels = 0for letter in 'education': if letter in 'aeiou': vowels += 1print(vowels) # 5
# Throwaway variable: when you only need to repeat somethingfor _ in range(3): print('Hello')while Loops
Section titled “while Loops”A while loop repeats as long as its condition is True. Use it when you do not know in advance how many iterations you need.
countdown = 3
while countdown > 0: print(countdown) # 3, 2, 1 countdown -= 1
print('Liftoff!')secret_number = 3guess = 0
while guess != secret_number: guess = int(input('Guess the number (1-5): ')) if guess != secret_number: print('Wrong! Try again.')
print('You got it!')The while True Pattern
Section titled “The while True Pattern”For input validation and retry logic, loop forever and break when you have what you need.
while True: text = input('Enter a whole number: ') try: number = int(text) break # Valid input, leave the loop except ValueError: print('Not a valid number, try again.')Controlling Loops
Section titled “Controlling Loops”| Statement | Effect |
|---|---|
break | Ends the loop immediately and skips any else block |
continue | Abandons the current iteration and jumps to the next one |
else | Runs only if the loop finished without hitting break |
pass | Does nothing. A placeholder for an empty block |
developers = ['Jess', 'Naomi', 'Tom']
# break: stop at the first matchfor developer in developers: if developer == 'Naomi': break print(developer) # Jess
# continue: skip one item and keep goingfor developer in developers: if developer == 'Naomi': continue print(developer) # Jess, Tomfor ... else
Section titled “for ... else”The else block of a loop is a clean way to express “search, and do something if nothing was found”.
numbers = [3, 7, 9]
for n in numbers: if n % 2 == 0: print('Found an even number') breakelse: print('No even numbers') # Runs, because there was no breakwords = ['sky', 'apple', 'rhythm', 'fly', 'orange']
for word in words: for letter in word: if letter.lower() in 'aeiou': print(f"'{word}' contains the vowel '{letter}'") break else: print(f"'{word}' has no vowels")Breaking Out of Nested Loops
Section titled “Breaking Out of Nested Loops”break exits only the innermost loop. To leave several levels at once, wrap the loops in a function and return.
def contains(matrix, target): for row in matrix: for value in row: if value == target: return True # Leaves both loops and the function return False
print(contains([[1, 2], [3, 4]], 3)) # Truerange()
Section titled “range()”range() produces a sequence of integers lazily: it stores only start, stop, and step, so range(1_000_000) uses the same tiny amount of memory as range(3).
| Call | Generates |
|---|---|
range(stop) | 0 up to stop - 1 |
range(start, stop) | start up to stop - 1 |
range(start, stop, step) | start up to stop - 1, moving by step |
The stop value is always excluded.
print(list(range(3))) # [0, 1, 2]print(list(range(1, 5))) # [1, 2, 3, 4]print(list(range(2, 11, 2))) # [2, 4, 6, 8, 10]print(list(range(40, 0, -10))) # [40, 30, 20, 10], a negative step counts downprint(list(range(5, 0))) # [], the default step is +1, so nothing is generated
for num in range(1, 4): print(num) # 1, 2, 3r = range(0, 10, 3) # 0, 3, 6, 9
print(len(r)) # 4print(6 in r) # True, checked arithmetically in O(1) timeprint(4 in r) # False
range(2.5) # TypeError: 'float' object cannot be interpreted as an integerrange(0, 10, 0) # ValueError: range() arg 3 must not be zeroPrefer Direct Iteration Over range(len(...))
Section titled “Prefer Direct Iteration Over range(len(...))”langs = ['Spanish', 'English', 'Russian']
for i in range(len(langs)): # Works, but clunky print(langs[i])
for lang in langs: # Preferred when you only need the items print(lang)
for i, lang in enumerate(langs): # Preferred when you also need the index print(i, lang)enumerate()
Section titled “enumerate()”enumerate() pairs each item with a counter, so you never need a manual index += 1. It yields (index, item) tuples, which you unpack in the loop header.
languages = ['Spanish', 'English', 'Russian', 'Chinese']
print(list(enumerate(languages)))# [(0, 'Spanish'), (1, 'English'), (2, 'Russian'), (3, 'Chinese')]
for index, language in enumerate(languages): print(f'Index {index}: {language}') # Starts at 0
for index, language in enumerate(languages, start=1): print(f'Language #{index}: {language}') # Starts at 1zip() combines several iterables into parallel tuples. It stops as soon as the shortest input runs out.
developers = ['Naomi', 'Dario', 'Jessica', 'Tom']ids = [1, 2, 3, 4]
print(list(zip(developers, ids)))# [('Naomi', 1), ('Dario', 2), ('Jessica', 3), ('Tom', 4)]
for name, dev_id in zip(developers, ids): print(f'Name: {name}, ID: {dev_id}')
print(dict(zip(['a', 'b'], [1, 2]))) # {'a': 1, 'b': 2}
pairs = [('a', 1), ('b', 2)]letters, numbers = zip(*pairs) # "Unzip": ('a', 'b') and (1, 2)Unequal Lengths
Section titled “Unequal Lengths”from itertools import zip_longest
names = ['Ann', 'Bob', 'Cy']ages = [31, 25]
print(list(zip(names, ages))) # [('Ann', 31), ('Bob', 25)], Cy is silently droppedprint(list(zip_longest(names, ages))) # [('Ann', 31), ('Bob', 25), ('Cy', None)]print(list(zip(names, ages, strict=True))) # ValueError: zip() argument 2 is shorter than argument 1Iterators Are Used Up
Section titled “Iterators Are Used Up”zip, map, filter, and enumerate return iterators, which can be traversed only once.
pairs = zip([1, 2], [3, 4])
print(list(pairs)) # [(1, 3), (2, 4)]print(list(pairs)) # [], already consumedList Comprehensions
Section titled “List Comprehensions”A comprehension builds a list from an iterable in one expression. The full pattern catalogue is in the Python Lists guide, so this section covers the essentials.
# Filter: keep matching items (the `if` goes at the end)even_numbers = [num for num in range(21) if num % 2 == 0]print(even_numbers) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Choose a value: if/else goes at the frontnumbers = [1, 2, 3, 4, 5]result = [(num, 'Even') if num % 2 == 0 else (num, 'Odd') for num in numbers]# [(1, 'Odd'), (2, 'Even'), (3, 'Odd'), (4, 'Even'), (5, 'Odd')]
# Related formssquares = {n: n ** 2 for n in range(3)} # Dict comprehension: {0: 0, 1: 1, 2: 4}unique_letters = {c for c in 'hello'} # Set comprehension: {'h', 'e', 'l', 'o'}total = sum(n * n for n in range(5)) # Generator expression: 30, builds no listFunctional Utilities
Section titled “Functional Utilities”| Function | Purpose | Returns |
|---|---|---|
filter(predicate, iterable) | Keeps items for which the predicate is truthy | A filter iterator |
map(function, iterable) | Applies a function to every item | A map iterator |
sum(iterable, start=0) | Adds up numbers | A number |
min(), max() | Smallest or largest item | One item |
any(iterable) | True if at least one item is truthy | A Boolean |
all(iterable) | True if every item is truthy | A Boolean |
# filter(): selectwords = ['tree', 'sky', 'mountain', 'river', 'cloud', 'sun']
def is_long_word(word): return len(word) > 4
long_words = list(filter(is_long_word, words))print(long_words) # ['mountain', 'river', 'cloud']
# map(): transformcelsius = [0, 10, 20, 30, 40]
def to_fahrenheit(temp): return (temp * 9 / 5) + 32
print(list(map(to_fahrenheit, celsius))) # [32.0, 50.0, 68.0, 86.0, 104.0]print(list(map(str, [1, 2, 3]))) # ['1', '2', '3']
# sum(): aggregatenumbers = [5, 10, 15, 20]print(sum(numbers)) # 50print(sum(numbers, 10)) # 60, the start value is added too
# any() / all(): testprint(any(n > 15 for n in numbers)) # Trueprint(all(n > 15 for n in numbers)) # FalseThree Ways to Filter
Section titled “Three Ways to Filter”numbers = [1, 2, 3, 4, 5]evens = [n for n in numbers if n % 2 == 0] # [2, 4]Usually the most readable choice.
numbers = [1, 2, 3, 4, 5]evens = list(filter(lambda n: n % 2 == 0, numbers)) # [2, 4]Fine when you already have a named predicate function.
numbers = [1, 2, 3, 4, 5]evens = []for n in numbers: if n % 2 == 0: evens.append(n)Best when the logic grows beyond a single condition.
Lambda Functions
Section titled “Lambda Functions”A lambda is a small, anonymous function written inline: lambda parameters: expression. It can take any number of parameters but contains a single expression, whose value is returned automatically.
numbers = [1, 2, 3, 4, 5]
print((lambda x: x + 1)(5)) # 6, defined and called at onceprint(list(filter(lambda x: x % 2 == 0, numbers))) # [2, 4]
people = [('Ann', 31), ('Bob', 25)]print(sorted(people, key=lambda p: p[1])) # [('Bob', 25), ('Ann', 31)]Style Guidelines
Section titled “Style Guidelines”1. Do not assign a lambda to a name. If a function needs a name, use def. PEP 8 recommends this, and named functions show up properly in error tracebacks (a lambda’s name is just <lambda>).
square = lambda x: x ** 2 # Discouraged
def square(num): # Preferred return num ** 22. Keep lambdas simple. Branching or multi-step logic belongs in a regular function.
# Discouraged: hard to readresult = (lambda x: (x**2 + 2*x - 1) if x > 0 else (x**3 - x + 4))(3)
# Preferreddef calculate_expression(x): if x > 0: return x**2 + 2*x - 1 return x**3 - x + 4
print(calculate_expression(3)) # 14Performance Notes
Section titled “Performance Notes”A loop’s total cost is the number of iterations multiplied by the cost of its body. The helpers themselves are cheap.
| Tool | Time | Memory | Note |
|---|---|---|---|
for / while | O(n) iterations | O(1) extra | Cost depends on the loop body |
range(...) | O(1) to create | O(1) | x in range(...) is also O(1) |
list(range(...)) | O(n) | O(n) | Builds every integer in memory |
enumerate(), zip() | O(n) | O(1) extra | Lazy, items are produced on demand |
| List comprehension | O(n) | O(n) | Builds the whole list |
| Generator expression | O(n) | O(1) | Produces one item at a time |
| Nested loops | O(N * M) | O(1) extra | Cost multiplies with each level |
Choosing the Right Tool
Section titled “Choosing the Right Tool”-
Do you have a collection or a known number of repeats? Use a
forloop, withrange()when you just need to count. -
Do you need to repeat until something changes? Use a
whileloop, and make sure the condition can become false. -
Do you need the position as well as the item? Use
enumerate()instead ofrange(len(...)). -
Are you reading two or more sequences together? Use
zip(), withstrict=Trueif the lengths must match. -
Are you building a new list? Use a comprehension. Fall back to a plain loop when the logic gets complicated.
Common Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Fix |
|---|---|---|
Forgetting to update the while condition | Infinite loop | Change the variable inside the loop, or break |
| Adding or removing list items while looping over it | Items get skipped | Loop over a copy or build a new list with a comprehension |
for i in range(len(items)) | Clunky and error-prone | for item in items or enumerate(items) |
range(1, 10) expecting 10 to be included | stop is excluded | range(1, 11) |
break in a nested loop expecting a full exit | Only the inner loop ends | Use a function with return, or a flag |
Reusing a zip, map, or filter result | Iterators are exhausted after one pass | Convert to a list first |
print(map(...)) | Shows a map object, not values | print(list(map(...))) |
zip() on lists of different lengths | Extra items are silently dropped | strict=True or zip_longest |
| Using the loop variable after the loop | It keeps its last value, or is undefined if the loop never ran | Do not rely on it, or initialize it before the loop |
| Assigning a lambda to a variable | Violates PEP 8, poor tracebacks | Use def |
Best Practices Checklist
Section titled “Best Practices Checklist”- Loop directly over items, and use
enumerate()when you need the index. - Use
zip()for parallel iteration, and addstrict=Truewhen lengths must match. - Use
breakandfor ... elsefor searches, and wrap nested searches in a function. - Guarantee that every
whileloop can end. - Prefer comprehensions to
map()andfilter()for simple transformations. - Never modify a list while iterating over it.
- Keep lambdas to one short expression, and use
deffor everything else. - Convert iterators with
list()when you need to reuse or print the results.