Essay
Learning Python, Part 2: Decisions and Loops
Study notes on comparisons, if and elif, for and while loops, accumulators and nested loops, with invented examples. Written entirely by an AI model.
Part 1 covered values. This part is about control: choosing between actions, and repeating them.
Comparisons and logic
The six comparisons are ==, !=, <, <=, > and >=. Each gives True or False. A single = is assignment, so if x = 5: is a syntax error rather than a comparison.
- Python allows chains:
0 < x < 10means0 < x and x < 10. - Strings compare by Unicode code point, one character at a time. Capitals sort before lowercase letters, so
"Zebra" < "apple"isTrue. - Mixing types raises
TypeError:"5" < 6fails.
and, or and not combine conditions. Precedence runs not, then and, then or; add brackets rather than rely on memory. They also short-circuit, which makes this guard safe:
if i < len(word) and word[i] == "x":
print("found at", i)
When i is too large, the first test is False and the second is never evaluated, so there is no IndexError.
if, elif and else
def ticket_price(age):
if age < 4:
return 0
elif age < 13:
return 8
elif age < 65:
return 15
else:
return 10
Python tests the branches from top to bottom and runs the first one that is true. Everything after that is skipped, which means order matters. Swap the first two branches so the test is age < 13 before age < 4, and toddlers pay 8 instead of nothing, because the broader test catches them first. Put the most specific test first.
Use plain if statements, not elif, when several conditions can all be true at once and you want every matching action to run.
Decisions are also your first line of defence against crashes. Check for the dangerous case before you divide, index or take a square root:
def share(total, people):
if people == 0:
return None
return total / people
for loops and range
A for loop runs its body once per item in a sequence:
for colour in ["red", "gold", "jade"]:
print(colour.upper())
When you need counting, use range:
range(5)gives 0, 1, 2, 3, 4.range(2, 5)gives 2, 3, 4.range(10, 0, -3)gives 10, 7, 4, 1.
The stop value is never included. A step of zero raises ValueError, and an empty range such as range(5, 2) simply runs the body zero times.
The accumulator pattern
Most loops build up a result, and they all follow the same four steps:
- Start a variable at the identity for the operation:
0for a sum,1for a product,""for text,[]for a list. - Loop over the inputs.
- Update the variable inside the loop.
- Use it after the loop.
def savings_after(years, deposit, rate):
jar = 0.0
for year in range(years):
jar = (jar + deposit) * (1 + rate)
return jar
print(round(savings_after(3, 100, 0.05), 2)) # 331.01
A habit worth building: trace a loop on paper with a small table before running it.
| Pass | year |
jar after |
|---|---|---|
| 1 | 0 | 105.0 |
| 2 | 1 | 215.25 |
| 3 | 2 | 331.0125 |
If your accumulator starts at the wrong value, every answer is wrong in the same predictable way. That makes the table a quick way to find the mistake.
while loops
Use while when you do not know in advance how many passes you need.
def halvings(amount, floor):
steps = 0
while amount >= floor:
amount = amount / 2
steps += 1
return steps
print(halvings(100, 1)) # 7
The two risks with while are a condition that never becomes false (an infinite loop) and a condition that is false from the start, so the body never runs. Make sure something inside the loop moves the condition towards false.
Three shapes come up repeatedly:
- Interactive loop. Ask “again?” after each pass.
- Sentinel loop. Keep reading values until a special one, such as an empty line, signals the end.
- Post-test loop. Run the body at least once, then decide. Python has no
do...while, so writewhile True:andbreakwhen the exit condition is met.
total = 0
while True:
line = input("Add a number (blank to stop): ")
if line == "":
break
total += float(line)
print("Total:", total)
break leaves the loop. continue skips straight to the next pass.
Nested loops
An inner loop runs completely for every pass of the outer one.
for row in range(1, 4):
for col in range(1, 5):
print(row * col, end="\t")
print()
The inner body runs 3 × 4 = 12 times. The bare print() at the end of each row ends the line.
A classic use is testing whether a number is prime by trying divisors:
def is_prime(n):
if n < 2:
return False
d = 2
while d * d <= n:
if n % d == 0:
return False
d += 1
return True
Only divisors up to the square root need checking. If n has a factor larger than that, it also has a matching factor smaller than it.
Where to practise
Try Set A in Python Drills, section 2 (“Loops, recursion and nesting”). The bouncing-ball drill is a while loop with an accumulator. The packing drill in section 3 is a nested loop with a flag. Part 3 turns these ideas into reusable functions.