Control Flow
Learn how to make your programs smart by having them make decisions based on conditions.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Control flow is how your program decides what code to run based on conditions. Without it, programs would just run line by line, doing the same thing every time.
Think of control flow like a traffic light. The light checks conditions (time, sensors) and decides whether to show green, yellow, or red. Your program works the same way!
Before writing a single line of control flow, build this mental model — it explains every behaviour you'll encounter.
Rule 1: Python reads conditions top to bottom
It checks the first if , then each elif in order. The moment one is True, it runs that block and skips all the rest .
Even if multiple conditions would be True, only the first True branch executes. This is why order matters when writing elif chains.
else has no condition — it runs when none of the above conditions were True. It's optional but gives your program a guaranteed fallback.
When using >= ranges, always check the most specific / highest condition first .
The if statement is the simplest form of control flow. It checks a condition and runs code only if that condition is True .
What if you want to do something different when the condition is False ? Use else to specify an alternative action.
When you have more than two possibilities , use elif (short for "else if") to check multiple conditions.
Conditions use comparison operators to compare values. These always return True or False .
You can combine multiple conditions using logical operators : and , or , and not .
You don't always need to write == True or != "" . Python evaluates any value as either truthy or falsy in a condition — and knowing this makes your code cleaner and more Pythonic.
You can put an if statement inside another if statement. This is called nesting and is useful for complex decisions.
Deeply nested if statements are hard to read. Professional Python developers use a technique called guard clauses — checking for bad conditions early and exiting, which keeps the main logic flat and readable.
5 levels deep — hard to follow, easy to make mistakes
Each failure exits early — main logic is at ground level
Check for invalid input, missing data, or error conditions at the top. Once you've handled those, write the main happy-path logic without nesting. This is standard practice in professional codebases — it's called the early return pattern .
You'll use return properly when you learn functions in a later lesson. For now, just understand that flat code beats nested code.
Indentation is not optional in Python! It tells Python which code belongs to which block. Use 4 spaces (or 1 tab) for each level.
Python has a shorthand way to write simple if-else statements in one line. This is called the ternary operator or conditional expression .
value_if_true if condition else value_if_false
Python 3.10 introduced match/case — a cleaner way to check a value against multiple exact options. Think of it as a smarter, more readable alternative to a long elif chain when you're matching against specific values.
The case _: at the bottom is the wildcard — it matches anything that didn't match above (equivalent to else ).
The | symbol means "or" inside a case — very handy for grouping related values.
The same handful of patterns appear in almost every real program. Recognise them and you'll be able to write production-quality logic from day one.
Pattern 1: Input validation — reject bad data first
Validate before processing. Always check for invalid states first and give the user clear, specific feedback.
Pattern 2: Range banding — categorise a value
Range banding is used everywhere: credit scores, age groups, tax brackets, shipping rates, difficulty levels.
Pattern 3: Default value — use a fallback if nothing set
Pattern 4: Feature flags — enable/disable behaviour
Feature flags let you turn functionality on/off with a single variable change — widely used in production software for A/B testing and gradual rollouts.
This project uses every control flow concept from this lesson — if/elif/else, logical operators, truthy/falsy, ternary, and nested conditions — to solve a real business problem.
Can you add a check that prints "Free delivery!" if final_price >= 50 ? What about adding a loyalty points calculation: 1 point per £1 spent, but double points for members?
Writing correct if/elif/else logic is a skill. Here's the thinking process professionals use when turning requirements into code.
Before writing a single line, ask: "What are all the different things that could happen?" Write them in plain English first.
What happens with invalid, unexpected, or extreme values? Always ask:
For range checks: put the most specific condition first. For validation: check the most likely failure first. For priority: most important condition at the top.
Manually trace through your code with at least 3 test values — one for each branch, plus one edge case. Ask: "What value do I need to reach the else ?" If you can't answer, your logic might have a gap.
Now that you can make decisions, it's time to learn about loops ! Loops let you repeat code multiple times, which is essential for:
Lesson 4 complete — your programs can now make decisions!
You've mastered if, elif, else, logical operators, nested conditions, and the ternary expression. Your programs are no longer just top-to-bottom scripts — they can respond to different situations.
🚀 Up next: Loops — make Python repeat tasks automatically instead of copy-pasting code.
Practice quiz
In an if/elif/elif chain, how many branches run when several conditions are True?
- All matching branches
- Only the last True branch
- Only the first True branch
- None of them
Answer: Only the first True branch. Python checks top to bottom and runs only the first True branch, skipping the rest.
When using >= range checks like grades, which condition should come first?
- The highest / most specific threshold
- The lowest threshold
- The else branch
- Order does not matter
Answer: The highest / most specific threshold. With >= ranges, check the highest threshold first, or a broad early condition catches everything.
What does the else clause do in an if/elif/else chain?
- Checks one more condition
- Always runs
- Runs before the if
- Runs only when none of the above conditions were True
Answer: Runs only when none of the above conditions were True. else has no condition; it runs as a fallback when no earlier condition was True.
Which of these is a FALSY value in Python?
- "0" (the string)
An empty list is falsy. A non-empty string "0", a non-empty list [0], and -5 are all truthy.
What does the ternary expression "Adult" if age >= 18 else "Minor" return when age is 20?
- "Adult"
- "Minor"
- True
- 20
Answer: "Adult". Since 20 >= 18 is True, the expression returns "Adult".
What is the difference between = and == in a condition?
- They are interchangeable
- == assigns; = compares
- = assigns a value; == compares for equality
- Both compare values
Answer: = assigns a value; == compares for equality. = assigns a value to a variable; == tests whether two values are equal.
Which is the recommended (PEP 8) way to check for None?
- if value == None:
- if value is None:
- if value = None:
- if not value:
Answer: if value is None:. PEP 8 recommends 'is None' — it's more readable and technically correct.
What does the | symbol mean inside a match/case pattern, e.g. case "Saturday" | "Sunday":?
- Bitwise OR of bytes
- A pipe to another function
- String concatenation
- 'or' — the case matches any of the listed values
Answer: 'or' — the case matches any of the listed values. Inside a case, | means 'or', so the case matches any of the listed values.
What does case _: do in a match statement?
- Matches only underscores
- Acts as the wildcard / default, like else
- Raises an error
- Matches nothing
Answer: Acts as the wildcard / default, like else. case _: is the wildcard that matches anything not matched above, equivalent to else.
What is the key idea behind a guard clause (early return pattern)?
- Nest every condition deeply
- Always use match/case
- Reject bad cases early and return, keeping the main logic flat
- Avoid using else
Answer: Reject bad cases early and return, keeping the main logic flat. Guard clauses check for invalid cases first and exit early, keeping the happy path flat and readable.