Python course · Part 3: Decisions and loops · lab 3 of 7
Decisions and loops
Choosing between paths, refusing bad requests early, going through a list and building something from it, and the three truthiness traps that make Python code quietly wrong.
By the end you can
- Write conditions that read in the order they are checked
- Refuse bad input at the top of a function instead of nesting
- Build a result from a list with a loop, and stop early when you can
- Avoid the falsy-zero trap and know when to use is rather than ==
Easier if you did first
step 1 of 3
Choosing a path
if runs a block when something is true. elif is the next question, asked only if the earlier ones were false. else is everything left.
Order is the whole thing. Python checks them top to bottom and stops at the first match, so a wider condition above a narrower one swallows it. Put the most specific first.
The second idea here matters more than the first. When a function has conditions that mean refuse, check them at the top and return immediately. That is a guard clause, and it keeps the real work at the left margin instead of nested four levels deep inside ifs.
The alternative, nesting the work inside each check, is how functions become unreadable. Refuse early, then get on with it.
Write the three. The last one is all guard clauses.
# Nested: the real work drifts to the right.
def order(stock, qty):
if stock > 0:
if qty <= stock:
return "ok"
# Guard clauses: refusals at the top, work at the left.
def order(stock, qty):
if stock <= 0:
return "out of stock"
if qty > stock:
return "not enough left"
return "ok"What these words mean
- if / elif / else
- Checked top to bottom; the first true one wins.
- guard clause
- An early return for a case you refuse.
- and / or
- Combine conditions. and needs both, or needs either.
- not
- Flips a condition.
- early return
- Leaving a function the moment the answer is known.
Easy to get wrong
Checking total > 1000 before total > 5000
Most specific first
A total of 6000 matches the first test and never reaches the second, so your biggest customers get the smallest discount and nothing errors.
Wrapping the whole function body in if valid:
if not valid: return, then the body
Nesting pushes the real work rightwards and puts the refusal far from the condition that caused it. Guard clauses keep both where you can see them.
What we check
- Small jobs are small, including exactly 3
- The boundaries fall on the right side
- Nonsense page counts are refused
- A large total gets the largest discount, not the first one that matches
- The middle band is right at its boundary
- Membership only matters below the bands
- A member on a large total still gets the large discount, not both
- A good order is not refused
- Signing in is checked first
- Stock problems are told apart
- A zero quantity is caught before stock is looked at
Nothing printed yet. Run your code.