Boolean expressions, if statements, else and elif, nested decisions, while loops, for loops, counters, accumulators, and the skill of tracing programs step by step
Every program you have seen so far runs in a straight line: step one, step two, step three, done. That is useful for short procedures, but almost no real program works that way. Real programs make decisions. They do different things depending on what they find. They repeat actions many times without you writing the same line over and over again. They skip steps, branch into alternatives, and keep running until a condition is satisfied.
This chapter introduces the tools that give programs this power. Those tools are called control flow structures. The two most important are conditionals — which let programs choose between paths — and loops — which let programs repeat actions automatically. Understanding these structures is one of the most important transitions in learning to program.
The chapter also introduces program tracing: following a program step by step on paper to predict what it will do. Tracing is one of the most important skills a programmer can develop. It teaches you to think like the computer executing the code, not just the programmer who wrote it.
A login system needs to check whether a password matches. If it does, let the user in. If it does not, show an error. A game character should keep moving until it hits a wall. A program should add up every number in a list of 10,000 entries without you writing 10,000 addition steps. All three of these require non-linear control flow — the ability for a program to take different paths, or repeat itself, based on what it discovers while running. By the end of this chapter, you will have the tools to write all of them.
== comparison operator from the = assignment operator.range() and explain how it differs from a while loop.When a computer runs a program, it executes instructions one at a time. The flow of control is the path the computer takes through those instructions. In the simplest programs, control flows from the first line to the last in a straight, uninterrupted path.
But most real programs cannot follow a straight path. A login system needs to check whether a password is correct. An app needs to display different content depending on a user's settings. A program that sums a list of 10,000 numbers cannot have 10,000 addition lines written by hand. All of these require non-linear control flow — the program's path depends on something it discovers while running.
| Structure | What it does | Example use |
|---|---|---|
| Conditional | Chooses between paths based on a condition | If the score is above 60, print "Pass" |
| Loop | Repeats a block of instructions multiple times | Add each number in a list to a total |
| Function call | Jumps to a named block and returns (Chapter 9) | Call a function to compute a square root |
The most important skill in this chapter is learning to trace — to follow a program's execution step by step, on paper, predicting what each line does and what value each variable holds. A program is not a description. It is a precise set of instructions that execute in a specific order. Tracing teaches you to read programs the way the computer runs them, not the way the programmer intended them.
Before a program can choose between paths, it needs a way to ask a yes-or-no question. Those answers come from Boolean expressions. A Boolean expression is any expression that evaluates to exactly one of two values: True or False. There is no middle ground, no "maybe," and no "partially true."
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | Equal to | 5 == 5 | True |
!= | Not equal to | 5 != 3 | True |
< | Less than | 3 < 7 | True |
> | Greater than | 10 > 15 | False |
<= | Less than or equal to | 4 <= 4 | True |
>= | Greater than or equal to | 2 >= 9 | False |
In Python, a single = is the assignment operator — it sets a variable's value. A double == is the comparison operator — it asks whether two values are equal and returns True or False. Writing if x = 5: is a syntax error. Writing if x == 5: is a comparison. Mixing these up is the single most common beginner mistake in Python.
x = 10 # Assignment: x now holds the value 10 x == 10 # Comparison: asks "is x equal to 10?" → True x == 5 # Comparison: asks "is x equal to 5?" → False
| Operator | Meaning | Example | Result |
|---|---|---|---|
and | Both must be True | (3 < 5) and (7 > 4) | True |
or | At least one must be True | (3 < 1) or (7 > 4) | True |
not | Reverses True and False | not (5 == 5) | False |
You can think of these operators as mirrors of everyday language. "The score is above 60 and the student attended class" requires both conditions to hold. "The temperature is below 32 or it is raining" is satisfied by either condition. "The account is not locked" reverses the condition entirely. Boolean expressions become most powerful when they involve variables, because the result changes depending on the variable's value at any given moment.
temperature = 28 temperature > 30 # False — 28 is not greater than 30 temperature >= 20 # True — 28 is at least 20 temperature == 28 # True — 28 equals 28
Evaluate each expression as True or False. Assume x = 12, y = 5, z = 12.
x == 12y > xx == zx != zy <= 5x > 10 and y < 10y > 10 or z == 12not (x == z)An if statement tells the program: evaluate this condition. If it is True, execute this block of code. If it is False, skip it entirely. It is the simplest form of decision in programming, and it is the foundation for all the more complex conditional structures that follow.
if condition:
instructions to run if condition is True
The colon after the condition is required. The indented lines form the block that runs when the condition is True. Lines at the same indentation level belong to the same block. Python uses indentation — not brackets or keywords — to group lines together.
score = 85 if score >= 60: print("You passed.")
85 >= 60 is True. The indented block runs. Output: "You passed."42 >= 60 is False. The indented block is skipped entirely. Nothing is printed.In Python, indentation is part of the language's grammar. If the line inside an if block is not indented, Python raises an IndentationError. If it is indented but the if line is missing its colon, Python raises a SyntaxError. Both errors stop the program before it runs. Standard Python indentation is 4 spaces per level. Never mix tabs and spaces.
An if statement handles the case when a condition is True. But what should happen when it is False? The else clause provides a second path. An if-else structure always runs exactly one of the two blocks: if the condition is True, the if block runs; if it is False, the else block runs. There is no situation where both run, and no situation where neither runs.
score = 42 if score >= 60: print("You passed.") else: print("You did not pass.")
Many decisions have more than two possibilities. For this, Python provides elif (short for "else if"), which adds additional conditions to check when all preceding conditions were False. Python evaluates the chain from top to bottom and runs only the first branch whose condition is True. Once a branch runs, the rest are skipped.
grade = 73 if grade >= 90: letter = "A" elif grade >= 80: letter = "B" elif grade >= 70: letter = "C" elif grade >= 60: letter = "D" else: letter = "F" print("Your grade is:", letter)
73 >= 90: False. Skip this block.73 >= 80: False. Skip this block.73 >= 70: True. Run this block: letter = "C". Stop checking.elif grade >= 60 and else branches are never evaluated.For each value of the variable, trace the code and write the exact output.
score = 78 # change this value for each question if score >= 90: print("Distinction") elif score >= 60: print("Pass") else: print("Fail")
Sometimes a decision depends on more than one condition checked in sequence — not combined with and, but evaluated one inside the other. This is called nesting: placing one if statement inside another. The inner if only runs when the outer condition is True. This is useful when the second question only makes sense if the first question answered a certain way.
age = 20 has_ticket = True if age >= 18: if has_ticket: print("Welcome. Enjoy the event.") else: print("You need a ticket to enter.") else: print("You must be 18 or older.")
20 >= 18 True → enter outer if. has_ticket True → inner if runs. Output: "Welcome. Enjoy the event."20 >= 18 True → enter outer if. has_ticket False → inner else runs. Output: "You need a ticket to enter."15 >= 18 False → outer else runs. Output: "You must be 18 or older." The inner if is never reached.When both conditions need to be True and there are no separate alternatives for each, combining with and is often cleaner: if age >= 18 and has_ticket:. Nesting is preferable when the inner condition has its own else branch that only makes sense in context of the outer condition passing. Avoid nesting more than two or three levels deep — deep nesting is difficult to read and often signals that the logic should be restructured.
and condition. When does the combined version behave differently from the nested version? When does it behave the same?Suppose you need to print the numbers from 1 to 10. One approach is to write ten separate print statements. That works for ten numbers, but it is completely impractical for a thousand, let alone a million. More importantly, it requires you to know the count in advance, write each case by hand, and change every line if the task changes.
Loops solve this problem by describing the pattern once and letting the computer repeat it. A loop is a control structure that repeats a block of instructions multiple times — either a fixed number of times, or until a condition changes. Every loop has two essential components: a loop body (the block of instructions to repeat) and a stopping mechanism (something that eventually causes the loop to end). If a loop never stops, it runs forever. Understanding how loops stop is just as important as understanding how they run.
| Loop type | Best used when | Stopping mechanism |
|---|---|---|
| While loop | You repeat until a condition changes; count unknown in advance | Condition becomes False |
| For loop | You iterate through every item in a sequence; count is known | Sequence is exhausted |
A while loop checks a condition before each iteration. If the condition is True, the loop body runs. Then the condition is checked again. This continues until the condition becomes False, at which point the loop ends and execution continues with the next instruction after the loop.
while condition:
loop body
The loop body must include something that eventually makes the condition False. If nothing inside the loop changes the condition, the loop will run without stopping — an infinite loop.
count = 1 while count <= 5: print(count) count = count + 1 print("Done")
| Iteration | count (before check) | count <= 5 | Action | count (after) |
|---|---|---|---|---|
| 1 | 1 | True | print 1 | 2 |
| 2 | 2 | True | print 2 | 3 |
| 3 | 3 | True | print 3 | 4 |
| 4 | 4 | True | print 4 | 5 |
| 5 | 5 | True | print 5 | 6 |
| 6 | 6 | False | loop ends | — |
Output: 1 2 3 4 5 Done (each number on its own line, then "Done").
Notice that count = count + 1 is inside the loop body. This is essential: if count never changed, the condition count <= 5 would always be True, and the loop would never stop. Every while loop must include something in the body that moves the program toward the stopping condition.
While loops are especially useful when you need to keep asking for input until the user provides a valid response. You do not know in advance how many attempts will be needed — which is exactly when a while loop is more appropriate than a for loop.
password = input("Enter password: ") while password != "open_sesame": print("Incorrect. Try again.") password = input("Enter password: ") print("Access granted.")
count = 1, but change the condition to count <= 3. Complete a trace table. What is the output?n = 10 / while n > 0: / print(n) / n = n - 3. Complete a trace table. What are all values printed? What is the final value of n when the loop ends?x = 32 / while x > 1: / x = x // 2. (// is integer division: 7 // 2 = 3.)A for loop repeats a block of code once for each item in a sequence. Unlike a while loop, the for loop automatically moves through each item in order. You do not need to manually track a counter variable or write a condition that eventually becomes False. The loop ends naturally when all items have been processed.
for item in sequence:
loop body using item
Each iteration, item takes on the value of the next element in the sequence. When the sequence is exhausted, the loop ends automatically.
The range() function generates a sequence of integers. range(5) produces 0, 1, 2, 3, 4. range(1, 6) produces 1, 2, 3, 4, 5. The stop value is always excluded — the sequence goes up to, but does not include, the stop number.
for i in range(1, 6): print(i)
| Iteration | i | Action |
|---|---|---|
| 1 | 1 | print 1 |
| 2 | 2 | print 2 |
| 3 | 3 | print 3 |
| 4 | 4 | print 4 |
| 5 | 5 | print 5 |
| — | — | sequence exhausted, loop ends |
fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(fruit)
Output: apple, banana, cherry (each on its own line). Each iteration, fruit takes on the next value from the list.
| Situation | Better choice |
|---|---|
| You know exactly how many times to repeat | for loop with range() |
| You are processing every item in a list or sequence | for loop |
| You repeat until a condition changes | while loop |
| You do not know in advance how many iterations you need | while loop |
| You need input validation | while loop |
range(3) produce?range(2, 8) produce?range(0, 10, 2) produce?["red","green","blue"].range(10, 0, -1))Two patterns appear so frequently in loops that every programmer should recognize them immediately: counters and accumulators. Both involve a variable that is set to a starting value before the loop begins and updated systematically inside the loop body.
A counter is a variable that increases by a fixed amount each iteration, keeping track of how many times some condition has been met.
count = 0 for i in range(1, 11): if i % 2 == 0: count = count + 1 print("Even numbers between 1 and 10:", count)
The % operator returns the remainder after integer division. 7 % 3 is 1 (7 ÷ 3 = 2 remainder 1). 10 % 2 is 0 (10 divides evenly by 2). i % 2 == 0 is True when i is even, because even numbers leave no remainder when divided by 2. Modulo is used constantly in programming: checking divisibility, wrapping values around a range, and detecting periodic events.
An accumulator is a variable that collects a running total as the loop processes each item. The most common form is a sum accumulator, but accumulators can also concatenate strings, build lists, or track any value that grows with each iteration.
total = 0 numbers = [12, 7, 25, 3, 41, 18] for n in numbers: total = total + n print("Sum:", total)
| Iteration | n | total (before) | total (after) |
|---|---|---|---|
| 1 | 12 | 0 | 12 |
| 2 | 7 | 12 | 19 |
| 3 | 25 | 19 | 44 |
| 4 | 3 | 44 | 47 |
| 5 | 41 | 47 | 88 |
| 6 | 18 | 88 | 106 |
| — | — | — | Output: Sum: 106 |
A counter or accumulator must be assigned a starting value before the loop begins. If total = 0 were placed inside the loop body instead of before it, total would be reset to 0 at the start of every iteration, destroying the running total. Initialization outside the loop is not optional — it is part of the pattern.
total = 0 count = 0 numbers = [15, 8, 22, 6, 30] for n in numbers: total = total + n count = count + 1 average = total / count print("Count:", count) print("Total:", total) print("Average:", average)
Output: Count: 5 / Total: 81 / Average: 16.2. This pattern — accumulating a sum and counting items to compute an average — appears constantly in data processing, science, finance, and everyday programs.
i, i % 2, the condition result, and count for each iteration from i=1 to i=6.[5, 14, 3, 22, 8, 11, 1] are greater than 10. Show expected output.[2, 3, 4, 5]. What must the accumulator be initialized to? Why?[-3, 7, -1, 4, -9, 2, -5].An infinite loop is a loop that never ends because its stopping condition never becomes False. It is one of the most common and frustrating bugs in programming. The program appears to freeze or hang — it is actually running the same instructions over and over without ever moving forward. Understanding what causes infinite loops, and how to prevent them, is an essential part of writing correct code.
count = 1 while count <= 5: print(count) # count is never changed — loop runs forever
count <= 5 is always True because count never changes. The program prints 1 indefinitely.count = count + 1 inside the loop body. Now count increases each iteration and eventually becomes 6, making the condition False.An off-by-one error occurs when a loop runs one time too many or one time too few because the boundary condition is written incorrectly. It is called "off-by-one" because the error is usually exactly one iteration in the wrong direction.
# Intended to print 1 through 5 for i in range(1, 5): # Produces 1, 2, 3, 4 — misses 5 print(i) # Correct version for i in range(1, 6): # Produces 1, 2, 3, 4, 5 print(i)
range(1, 5) produces numbers from 1 up to but not including 5. The stop value is always excluded. This trips up many beginners: when you want to include the value 5 in your range, you must write range(1, 6). Similarly, in while loops, the difference between < and <= in the boundary condition determines whether the final value is included.
The most reliable method for debugging a loop is to trace it by hand. Take a small version of the data, trace the loop iteration by iteration in a table, and check whether the values change as expected. If the trace reveals unexpected behavior, the cause is usually one of: the wrong initial value, the wrong boundary condition (< vs. <=), or a missing or misplaced update to the loop variable.
You can also add print statements inside the loop temporarily to see what is happening at each step. These diagnostic prints reveal the state of your variables at every iteration. Remove them once the loop is working correctly.
total = 0 for i in range(1, 6): print("i is:", i, " total before:", total) total = total + i print(" total after:", total)
Each fragment contains an error. Identify the error type and write the corrected version.
What happens when you run this? What is missing? Write the fix.
What does this actually print? What should the range be?
What error will Python raise? What must be added, and where?
This prints 0–4, not 0–5. What single character change fixes it?
==, !=, <, >, <=, >=) compare values. Logical operators (and, or, not) combine conditions. The == comparison operator must not be confused with the = assignment operator.and are often cleaner when both conditions must hold without separate alternatives.range() function generates integer sequences. The stop value is excluded. For loops are best for counted repetition and processing every item in a known sequence.% modulo operator returns the remainder after division and is commonly used to check for even numbers and periodicity.==, !=, <, >, <=, >=.and, or, and not.% operator. Returns the remainder after integer division. 7 % 3 equals 1.range(1, 6) produces 1, 2, 3, 4, 5. Start
│
[Evaluate Condition]
│
┌────┴────┐
True False
│ │
[If Block] [Else Block]
│ │
└────┬─────┘
│
Continue
Start
│
[Evaluate Condition] ◄──────────┐
│ │
┌────┴────┐ │
True False │
│ │ │
[Loop Body] [Exit Loop] │
│ │
└──────────────────────────────┘
Start
│
[More items in sequence?] ◄─────┐
│ │
┌────┴────┐ │
Yes No │
│ │ │
[Set loop [Exit Loop] │
variable │
to next item] │
│ │
[Loop Body] │
│ │
└──────────────────────────────┘
x = 14 if x > 10: print("large") elif x > 5: print("medium") else: print("small")
total = 0 for i in range(1, 6): total = total + i print(total)
| Iteration | i | total (before adding) | total (after adding) |
|---|---|---|---|
| 1 | |||
| 2 | |||
| 3 | |||
| 4 | |||
| 5 |
What is the final output?
count = 0 while count < 5: print(count) print("Done")
elif keyword stands for ________.Trace each code fragment and write the exact output.
x = 8 if x > 10: print("A") elif x > 5: print("B") else: print("C")
for i in range(3): print(i * 2)
n = 1 while n <= 16: n = n * 2 print(n)
total = 0 for i in range(1, 5): if i % 2 == 0: total = total + i print(total)
a = True b = False print(a and b) print(a or b) print(not a)
7 x 1 = 7, 7 x 2 = 14, and so on through 7 x 10 = 70.[3, 16, 7, 22, 5, 14, 9, 8, 11, 20]. Use a single loop with a conditional inside it.scores = [78, 92, 65, 88, 71, 95, 83, 60, 77, 89] and tracks the highest score found so far. Print the highest score after the loop. (Hint: initialize highest = scores[0] before the loop.)Each problem contains an error. Identify the error type (syntax, logic, or runtime), explain what went wrong, and write the corrected version.
A student writes 5(2x − 3) and gets 10x − 3. What is the error? What is correct?
Identify the error and classify it. Explain why it occurs and write the fix.
What is missing? What type of error is this? Write the correct version.
There are two errors. Find both. What are their types? Write corrected code.
The code works for this value of n. A classmate says it should use elif. Explain why elif is preferable and what problem could arise if the conditions were not mutually exclusive.
Nearly every application that requires an account uses a loop to handle failed login attempts. Describe in pseudocode or Python how a while loop and a conditional together could implement a login system that: allows up to three attempts; prints a success message if the password matches; prints a lockout message if all three attempts fail.
A streaming service wants to recommend content based on a user's stated mood: "action", "comedy", "drama", or "documentary". Each mood maps to a different recommendation. Write pseudocode or Python code that reads the user's mood and prints the recommendation. Include an else branch for unrecognized moods.
A store tracks stock quantities. Write a program that processes stock = [0, 12, 3, 0, 7, 1, 0, 5, 9, 2] and counts: how many items are out of stock (quantity = 0); how many are low (1–5); how many are well-stocked (above 5). Print all three counts at the end.
temps = [22, 28, 31, 25, 29, 33, 30, 27, 24, 26, 31, 28, 22, 20, 25, 29, 34, 32, 27, 23, 21, 28, 30, 31, 26, 24, 29, 33, 28, 25]
Using this list of 30 daily temperatures, write a program that: counts how many days exceeded 30°C; finds the total of all temperatures; computes the monthly average. Print all three results.
1010 in binary greater than, equal to, or less than 1001 in binary? Explain how a program might use a comparison operator to test this relationship once both values are stored as integers.name holds a string. Write an if statement that checks whether name equals "admin" and prints "Access granted" if it does and "Access denied" if it does not.= and == in Python with an example of each.range(2, 9) produce? How many values does it generate?x = 5 / if x > 3: print("big") / elif x > 1: print("medium") / else: print("small")total = 0 / for i in range(1, 5): / total = total + i / print(total)n = 10 / while n > 2: / print(n) / n = n // 2[4, 15, 6, 22, 3, 18, 9] are greater than 10.[7, 3, 11, 5, 9, 2].while count < 10: / print(count). What is wrong? What type of error is this?for i in range(1, 10): intending to include 10 in the output. What should they write instead?if score = 100: print("Perfect"). Identify the error, classify it, and write the corrected line.Chapter 8 gave you the tools to make programs that decide and repeat. As programs grow larger, writing all the instructions in one block becomes unmanageable — the same logic gets repeated in multiple places, and the code becomes difficult to understand, test, and fix. Chapter 9 introduces functions: named, reusable blocks of code that solve a specific part of a problem. Functions let you write an instruction once, give it a name, and call it as many times as needed from anywhere in a program. You will learn to define functions, pass values into them using parameters, and receive results using return values. Functions are the foundation of decomposition in programming — breaking a large, complex problem into small, clearly named, independently tested parts. Every skill you built in Chapter 8 will be used inside functions in Chapter 9 and beyond.