Control Flow, Loops, and Iteration Patterns

Control flow is how your program decides what to do next. In data structures and algorithms (DSA), you spend most of your time branching on conditions and looping over collections. This page covers the exact tools you need. If you have not read Python for DSA yet, start there, then come back.

Making decisions: if, elif, else#

Python evaluates conditions top to bottom and runs the first branch that is true. Only one branch runs.

 1def classify(n):
 2    if n < 0:
 3        return "negative"
 4    elif n == 0:
 5        return "zero"
 6    else:
 7        return "positive"
 8
 9print(classify(-5))   # negative
10print(classify(0))    # zero
11print(classify(42))   # positive

You can chain as many elif branches as you need. The else is optional. Conditions can use comparisons (<, <=, ==, !=, >, >=) and the boolean operators and, or, not.

1age = 20
2has_ticket = True
3
4if age >= 18 and has_ticket:
5    print("Admit")
6elif age >= 18 and not has_ticket:
7    print("Buy a ticket")
8else:
9    print("Too young")

Python treats empty collections, 0, None, and False as falsy. Everything else is truthy. This lets you write clean guard checks.

1def first_or_none(items):
2    if not items:          # True when the list is empty
3        return None
4    return items[0]
5
6print(first_or_none([]))       # None
7print(first_or_none([9, 8]))   # 9

Looping with for and range#

A for loop walks through the items of any iterable (a list, string, range, and more). Use range when you need numeric indices or a fixed count.

1for i in range(5):
2    print(i)          # 0 1 2 3 4
3
4# range(start, stop, step)
5for i in range(2, 11, 2):
6    print(i)          # 2 4 6 8 10

range(stop) goes from 0 up to but not including stop. This half-open convention matches how array indices work and prevents off-by-one bugs.

while loops#

Use while when you do not know the iteration count in advance, such as looping until a pointer meets a condition.

 1def binary_search(sorted_nums, target):
 2    low, high = 0, len(sorted_nums) - 1
 3    while low <= high:
 4        mid = (low + high) // 2
 5        if sorted_nums[mid] == target:
 6            return mid
 7        elif sorted_nums[mid] < target:
 8            low = mid + 1
 9        else:
10            high = mid - 1
11    return -1
12
13print(binary_search([1, 3, 5, 7, 9], 7))   # 3

break and continue#

break exits the loop immediately. continue skips to the next iteration.

 1# Stop at the first even number
 2for n in [1, 3, 4, 7, 8]:
 3    if n % 2 == 0:
 4        print("first even:", n)
 5        break
 6
 7# Sum only the odd numbers
 8total = 0
 9for n in range(1, 11):
10    if n % 2 == 0:
11        continue
12    total += n
13print(total)   # 25

for-else: the loop that ran to completion#

The else block on a loop runs only if the loop finished without hitting break. This is perfect for search-and-report patterns.

 1def find_factor(n):
 2    for d in range(2, n):
 3        if n % d == 0:
 4            print(f"{n} is divisible by {d}")
 5            break
 6    else:
 7        print(f"{n} is prime")
 8
 9find_factor(15)   # 15 is divisible by 3
10find_factor(13)   # 13 is prime

Iterating with index vs value#

Often you want both the position and the value. Use enumerate instead of manually tracking a counter.

 1letters = ["a", "b", "c"]
 2
 3# index only, harder to read
 4for i in range(len(letters)):
 5    print(i, letters[i])
 6
 7# index and value together, preferred
 8for i, letter in enumerate(letters):
 9    print(i, letter)
10
11# start numbering from 1
12for rank, letter in enumerate(letters, start=1):
13    print(rank, letter)

Reversing and pairing iterables#

reversed walks a sequence backward without building a new list. zip pairs up multiple iterables element by element, stopping at the shortest one.

 1for x in reversed([10, 20, 30]):
 2    print(x)          # 30 20 10
 3
 4names = ["Ada", "Alan", "Grace"]
 5scores = [95, 88, 91]
 6for name, score in zip(names, scores):
 7    print(f"{name}: {score}")
 8
 9# zip with enumerate for index, name, and score
10for i, (name, score) in enumerate(zip(names, scores)):
11    print(i, name, score)

These patterns show up constantly once you start the 60-day curriculum. When you analyze how many times a loop runs, you are reasoning about time complexity, so keep the Big-O cheat sheet handy and apply these loops in the algorithm lessons.