InterviewPrepKit

Home / Learn / Algorithms & Data Structures with Python

Control Flow: if, for, while

So far a program has been a straight line: every instruction runs once, top to bottom. Control flow is how you change that order. It lets a program make decisions (“do this only when the balance is negative”) and repeat work (“do this for every item in the list”). Almost every useful program is built from these two ideas: choosing and repeating.

Boolean conditions

A decision needs a yes-or-no question. In Python that question is any expression that produces a boolean — a value that is either True or False. The comparison operators produce booleans:

print(3 < 5)      # -> True
print(3 > 5)      # -> False
print(4 == 4)     # -> True    == asks "are these equal?"
print(4 != 4)     # -> False   != asks "are these different?"
print(2 <= 2)     # -> True    less-than-or-equal

Note == (compare) is different from = (assign). x = 4 stores 4 in x; x == 4 asks whether x is 4.

You combine conditions with and, or, and not:

age = 20
print(age >= 18 and age < 65)   # -> True    both sides must hold
print(age < 13 or age > 64)     # -> False   either side may hold
print(not age == 20)            # -> False   flips True/False

if / elif / else

An if statement runs a block of code only when its condition is True.

temperature = 30
if temperature > 25:
    print("warm")
# -> warm

The line ends with a colon :, and the code it controls is written on the next line, indented (shifted right by spaces). That indented group is called a block. The block runs when the condition is true and is skipped when it is false.

Add else for the “otherwise” case, and elif (short for “else if”) for extra cases checked in order:

score = 72
if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")
else:
    print("below C")
# -> C

Python checks the conditions top to bottom and runs the block for the first one that is true, then skips the rest. Because score >= 70 is the first true condition, it prints C and never looks at else. Picture that search as a chain of questions, where each false answer drops you to the next test:

flowchart TD
  A["score >= 90 ?"] -->|True| B["print A"]
  A -->|False| C["score >= 80 ?"]
  C -->|True| D["print B"]
  C -->|False| E["score >= 70 ?"]
  E -->|True| F["print C"]
  E -->|False| G["print below C"]

Indentation is the grouping

Python has no braces or begin/end keywords. The indentation is the structure. Every line in a block must be indented the same amount (four spaces is standard). Getting it wrong is an error, not a style issue:

if True:
print("oops")     # -> IndentationError: expected an indented block

Only the indented lines belong to the if. A line back at the outer level runs regardless of the condition:

x = 1
if x > 100:
    print("big")     # skipped, x is not > 100
print("done")        # -> done   (runs either way)

for loops

A loop repeats a block. A for loop repeats it once for each item in a sequence, handing you the item each time through a variable you name.

for fruit in ["apple", "pear", "plum"]:
    print(fruit)
# -> apple
# -> pear
# -> plum

Read it as: “for each fruit in this list, run the block.” The variable fruit takes the first value on the first pass, the second on the next, and so on until the sequence is exhausted. One full pass through the block is called an iteration.

range: looping a fixed number of times

Often you want to repeat something a set number of times, or count. range(n) produces the whole numbers 0, 1, ..., n-1:

for i in range(4):
    print(i)
# -> 0
# -> 1
# -> 2
# -> 3

It starts at 0 and stops before the number you give, so range(4) yields four values. You can pass a start and a step too, as range(start, stop, step):

for i in range(2, 10, 2):
    print(i)
# -> 2
# -> 4
# -> 6
# -> 8

Here it starts at 2, stops before 10, and adds 2 each time. range never includes the stop value. A negative step counts down:

for i in range(3, 0, -1):
    print(i)
# -> 3
# -> 2
# -> 1

range does not build a list of all the numbers up front; it produces each one as the loop asks for it, so range(1000000) uses the same tiny amount of memory as range(3). That is O(1) space.

enumerate: index and value together

Sometimes you need both the position (index) of an item and the item itself. enumerate gives you both, so you do not have to track a counter by hand:

colors = ["red", "green", "blue"]
for index, color in enumerate(colors):
    print(index, color)
# -> 0 red
# -> 1 green
# -> 2 blue

Each pass unpacks a pair into two variables: index (starting at 0) and color. This is cleaner and less error-prone than manually writing i = i + 1.

while loops

A while loop repeats its block as long as a condition stays true. Use it when you do not know in advance how many iterations you need.

count = 3
while count > 0:
    print(count)
    count = count - 1
print("liftoff")
# -> 3
# -> 2
# -> 1
# -> liftoff

Python checks the condition before each pass. When count reaches 0, count > 0 is False, the loop stops, and the program continues after it. The block must eventually make the condition false — here, count = count - 1 moves it toward the exit.

The infinite-loop pitfall

If the condition never becomes false, the loop never ends. This is the most common while bug:

count = 3
while count > 0:
    print(count)
    # forgot to change count -> prints 3 forever

Because nothing updates count, the condition stays true and the program hangs. Whenever you write a while, find the line that moves it toward stopping and make sure it always runs. (If a program does get stuck like this in a terminal, Ctrl+C stops it.)

break and continue

Two keywords give you finer control inside any loop.

break exits the loop immediately, skipping the rest of the iterations:

for n in [4, 8, 15, 16, 23]:
    if n > 10:
        break
    print(n)
# -> 4
# -> 8

The loop stops the moment it meets 15, so 16 and 23 are never seen.

continue skips the rest of the current iteration and jumps straight to the next one:

for n in range(6):
    if n % 2 == 1:      # n % 2 is the remainder; 1 means odd
        continue
    print(n)
# -> 0
# -> 2
# -> 4

On odd numbers, continue jumps past the print, so only the even numbers are shown.

Nested loops

A loop can contain another loop. The inner loop runs fully on each pass of the outer loop.

for row in range(1, 4):
    for col in range(1, 4):
        print(row * col, end=" ")
    print()   # newline after each row
# -> 1 2 3
# -> 2 4 6
# -> 3 6 9

The outer loop fixes row, then the inner loop walks col through all its values before the outer loop advances. If the outer loop runs n times and the inner runs m times, the inner block runs n times m in total. When both loops go over the same collection of size n, that is O(n squared) time — worth noticing, because it grows fast: doubling n roughly quadruples the work.

Worked example: FizzBuzz

A classic first exercise ties these pieces together. Print the numbers 1 to 15, but replace multiples of 3 with Fizz, multiples of 5 with Buzz, and multiples of both with FizzBuzz.

for n in range(1, 16):
    if n % 3 == 0 and n % 5 == 0:
        print("FizzBuzz")
    elif n % 3 == 0:
        print("Fizz")
    elif n % 5 == 0:
        print("Buzz")
    else:
        print(n)
# -> 1
# -> 2
# -> Fizz
# -> 4
# -> Buzz
# -> Fizz
# -> 7
# ... 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz

The order of the branches matters: the “both” case is checked first, because a multiple of 15 also passes the % 3 and % 5 tests on their own. If n % 3 == 0 came first, 15 would print Fizz and never reach the combined case. This loop runs a fixed amount of work per number, so it is O(n) time for n numbers.

Common pitfalls

  • range stops one early. range(1, 5) gives 1, 2, 3, 4, not 5. To include a number, go one past it.
  • Off-by-one and empty ranges. range(5, 1) (start above stop, default step +1) produces nothing, so the loop body never runs. Check your bounds when a loop is silently doing nothing.
  • Forgetting to advance a while. Every while needs a line that moves the condition toward False, or it loops forever.
  • Changing a list while looping over it. Adding or removing items from the same list you are iterating causes items to be skipped or repeated. Loop over a copy, or build a new list instead.
  • = vs == in a condition. A condition uses ==. Writing if x = 5: is a SyntaxError.

Practice

  1. Print every number from 1 to 20, but on each multiple of 4 print "four!" instead of the number.
  2. Use a while loop to sum the numbers 1 through 100, then print the total. (The answer is 5050.)
  3. Given words = ["hi", "world", "a", "python"], use enumerate to print only the words longer than 2 characters together with their index.
Report a bug