Control Flow: Beginner
Every program you have written so far runs each line exactly once, from the first to the last. An if statement adds a decision: it holds a condition, and the lines under it run only when that condition is True. When the condition is False, Python skips those lines and carries on below them.
Python reads this in 3 steps. First, it compares the number stored in balance with 100. Second, that comparison produces a boolean, here True. Third, it uses that boolean to decide: True runs the indented print, and False skips it. Had balance been 90, the comparison would produce False, the print would never run, and the program would print nothing at all.
What a condition is made of
A condition is any expression whose value is a boolean. You met that type in Data Types, where its only values were True and False. The 6 comparison operators below each take 2 values and produce one boolean, which makes them the usual way to build a condition. With balance = 120, each row shows what the comparison returns.
| Operator | Meaning | Example | Result |
|---|---|---|---|
| `==` | equal to | `balance == 120` | True |
| `!=` | not equal to | `balance != 120` | False |
| `>` | greater than | `balance > 200` | False |
| `<` | less than | `balance < 200` | True |
| `>=` | greater than or equal to | `balance >= 120` | True |
| `<=` | less than or equal to | `balance <= 100` | False |
A single = stores a value, and a double == asks whether 2 values are equal. Writing if balance = 100: is a syntax error, and Python refuses to run the file. When a condition tests equality it must use ==, because a single = is an assignment and is not allowed in an if header.
The colon and the indent
The header line ends with a colon. Every line that belongs to the if is indented by 4 spaces underneath it, and together those lines are the statement's block. The block ends at the first line that returns to the left margin. That line runs no matter what the condition was, because it sits outside the block. Leave the indent out and Python stops before running anything, with the message IndentationError: expected an indented block.
- ▸The keyword
if, followed by a condition that produces True or False - ▸A colon at the end of the header line, with nothing after it
- ▸One or more lines indented 4 spaces, which run only when the condition is True
Watching a True condition
The animation below stores 21 in age and tests age >= 18. The comparison produces True, so both indented prints run in order. The final print is back at the left margin, so it belongs to the program rather than to the if, and it runs after the block finishes. Step through it and watch the highlight move into the block and out again.
1age = 2123if age >= 18:4 print("You are an adult")5 print("You can vote")67print("This always runs")
Watching a False condition
This run stores 15 in temperature and tests temperature > 30. The comparison produces False, so Python jumps over the 2 indented lines without touching them, and the first thing it prints is the line after the block. Nothing inside a skipped block has any effect, which is the whole point of putting it inside an if.
1temperature = 1523if temperature > 30:4 print("It's hot outside")5 print("Turn on the AC")67print("Weather check complete")
Several if statements in a row
Each if statement is checked on its own, so a program can hold any number of them, and each decides only about its own block. Below, 3 checks run against the same order. Predict which lines print before you reveal the output: the total is 85 and the coupon code is SAVE10.
The first condition, 85 > 50, is True, so the shipping line prints. The coupon test compares "SAVE10" with "SAVE20", 2 different strings, so == returns False and the discount line is skipped. The third condition fails too, because 85 is below 200. The final print has no indent, so it runs regardless, and the order total appears last.
What does this program print?
When you write a header yourself, check 2 things. The operator must point the way the rule means: a rule that warns above 30 needs >, because < would warn on cool days and == would warn only at exactly 30. And the line must end with a colon, which marks where the indented block begins.
An if on its own answers one question: run this block or skip it. Adding else gives Python a second block to run when the condition is False. The 2 blocks are alternatives. On any single run exactly one of them executes, so Python can't skip both or run both.
The else line sits at the same indent as its if, ends with a colon, and carries no condition. It needs none, because it covers every case the if condition did not. Here 16 >= 18 is False, so Python skips the first block and runs the second, printing Child ticket.
A branch can do more than print
Each block can hold as many lines as the decision needs, including assignments. The animation below picks a shipping fee: an order of 50 or more ships free, and anything less pays 5. After the branch finishes, the program continues with whichever value of shipping the chosen block set, so the grand total depends on that choice.
1order_total = 4223if order_total >= 50:4 print("Free shipping")5 shipping = 06else:7 print("Shipping fee added")8 shipping = 5910grand_total = order_total + shipping11print("Grand total:", grand_total)
42 >= 50 is False, so the else block sets shipping to 5.
Change order_total in your head and trace it again. The table below lists 3 runs: the condition's value, the block that runs, and what prints. Look at the middle row, where the total is exactly 50. >= includes the equal case, so 50 ships free. Had the condition been order_total > 50, that same order would pay the fee.
| order_total | order_total >= 50 | Block that runs | Printed |
|---|---|---|---|
| 30 | False | else | Shipping fee added, then Grand total: 35 |
| 50 | True | if | Free shipping, then Grand total: 50 |
| 75 | True | if | Free shipping, then Grand total: 75 |
Exactly one branch, every time
- Runs the block or skips it
- On a False condition, nothing happens
- Use when the False case needs no action
- Runs the first block or the second
- On a False condition, the else block runs
- Use when both outcomes need code
The remainder operator from Basic Operators makes a natural 2-way decision. seat_number % 2 is what's left after dividing by 2, so it is 0 for an even number and 1 for an odd one. Comparing that remainder to 0 splits every integer into exactly 2 groups, which is what if and else need. Predict the output for seat 17.
Dividing 17 by 2 leaves a remainder of 1, so 1 == 0 is False, the else block runs, and the aisle line prints. The last print is outside both blocks and prints the seat number afterwards, whichever branch ran.
- Keep else at the same indent as its if
- End the else line with a colon and put nothing between else and the colon
- Put code for the False case inside else rather than after the if
- Write a condition after else, such as else age < 18:, which is a syntax error
- Use a second if to handle the False case, because the 2 conditions can drift apart
- Leave a block empty, because Python requires at least 1 line in it
What does this program print?
The most frequent else mistake is giving it a condition. A line such as else order_total < 50: makes Python reject the whole file before a single line runs, because else already means every case the if condition missed. Deleting the condition and leaving else: restores the branch.
Many decisions have more than 2 outcomes: a grade band, a shipping tier, a greeting that depends on the time of day. elif, short for else-if, adds another condition to the chain. Python tests the conditions from top to bottom, runs the block of the first one that is True, and skips every condition after it without evaluating them. The final else runs only when every condition before it was False.
With score = 83, Python tests 83 >= 90 first. It comes out False, so Python moves to the next condition. 83 >= 80 is True, so grade becomes "B" and the chain is finished. The condition 83 >= 70 is also True, but it is never evaluated, because the chain stopped at the first match. One block in a chain runs, however many of its conditions would have passed.
Tracing a chain step by step
The animation prices a ride by distance. Watch which conditions are evaluated for a 12 km trip: the first is tested and fails, the second is tested and passes, and the highlight never reaches the third or the else.
1distance_km = 1223if distance_km <= 5:4 fare = 45elif distance_km <= 15:6 fare = 97elif distance_km <= 30:8 fare = 159else:10 fare = 251112print("Fare:", fare)
Python tests 2 conditions and stops at the first True one.
| distance_km | Conditions tested | First True condition | fare |
|---|---|---|---|
| 3 | 1 | `distance_km <= 5` | 4 |
| 12 | 2 | `distance_km <= 15` | 9 |
| 30 | 3 | `distance_km <= 30` | 15 |
| 45 | 3 | none, so else runs | 25 |
Order decides the answer
Because the first True condition wins, the order of the conditions is part of the logic. The program below has the same 3 bands as the grade example, written from lowest threshold to highest. Predict what a score of 95 prints.
A score of 95 is at least 70, so the first condition is True and Python prints C. The conditions that would have produced A or B are never reached. When conditions overlap, put the most specific one first. In a chain of >= tests that is the highest threshold, and in a chain of <= tests it is the lowest.
A chain against separate if statements
A set of 3 separate if statements looks similar on the page but behaves differently. Each one is tested independently, so every condition that is True runs its block. The program below runs the same 3 conditions both ways against a score of 95.
The chain prints 1 line, because it stops at the first match. The separate statements print 3, because 95 satisfies all 3 conditions and nothing stops the later ones from running. When the outcomes are meant to exclude each other, a chain is the right tool. When several outcomes can apply at once, separate if statements are.
- Conditions are tested top to bottom, and testing stops at the first True
- Exactly one block runs when there is an else, and at most one runs without it
- A chain may hold any number of elif lines and at most 1 else, which comes last
- Each elif has its own condition and colon, and else has a colon and no condition
What does this program print?
Turning a rule stated in words into a chain takes 3 decisions: which comparison each band needs, which band is tested first, and which keyword opens each later band. With < tests the lowest threshold comes first, each later band starts with elif, and the last band, which has no upper limit, becomes the else.
Real decisions often depend on 2 facts at once. A discount applies when the customer is a student and today is Tuesday. A jacket is needed when it rains or the wind is strong. Python's boolean operators join conditions into one: and is True only when both sides are True, or is True when at least one side is True, and not flips a single boolean to its opposite.
| left | right | left and right | left or right |
|---|---|---|---|
| True | True | True | True |
| True | False | False | True |
| False | True | False | True |
| False | False | False | False |
The table has 4 rows because 2 booleans have 4 combinations. Read it with the same question each time: and asks whether both are True, and only the first row says yes. or asks whether either is True, and only the last row says no. not True is False, and not False is True.
Python evaluates each side to a boolean first, then applies the operator. is_student is already True and day == "Tuesday" produces True. That makes True and True evaluate to True, so the block runs. Change day to "Friday" and the right side becomes False. Now True and False is False and the block is skipped.
Conditions are values
A combined condition is an expression like any other, so it can be stored in a variable and printed. The animation below builds 2 booleans and prints them before using one in an if together with not. Follow each comparison as it collapses to True or False.
1age = 242member = False3day = "Tuesday"45student_rate = age <= 25 and day == "Tuesday"6member_rate = member or day == "Tuesday"78print("Student rate:", student_rate)9print("Member rate:", member_rate)1011if student_rate and not member:12 print("Charge 8")13else:14 print("Charge 12")
Each combined condition becomes a single True or False before the if uses it.
| Expression | Step 1 | Step 2 | Value |
|---|---|---|---|
| `age <= 25 and day == "Tuesday"` | `True and True` | no further step | True |
| `member or day == "Tuesday"` | `False or True` | no further step | True |
| `student_rate and not member` | `True and not False` | `True and True` | True |
Which operator applies first
When one condition holds both and and or, Python applies not first, then and, then or, the way multiplication happens before addition in arithmetic. Parentheses override that order, and they also make the intent visible to whoever reads the line next. The 2 prints below hold the same 3 variables and the same operators, and they disagree.
In the first line Python groups is_holiday and is_open together to get False. What remains, True or False, is True. The parentheses in the second line make Python evaluate the or first and get True, and then True and is_open comes out False. Whenever and and or share a line, add the parentheses, even when the default order already does what you want.
Putting 3 conditions to work
The first condition is True and not False, which is True and True, so the walk line prints. The second is False or True, so the jacket line prints as well. The third is True and False, so nothing prints for warm rain. Each if decides on its own, which is why 2 of the 3 blocks ran.
- Write each side of and/or as a complete comparison
- Add parentheses when and and or appear on one line
- Name booleans so that a line like if raining or windy: reads as a sentence
- Write day == 6 or 7, which Python reads as (day == 6) or 7 and never as a second comparison
- Rely on the default order to separate and from or
- Compare a boolean to True, if raining == True:, when if raining: says the same
What does this program print?
Picking between and and or follows the wording of the rule. If every part must hold, use and. If any one part is enough, use or. A rule that says a parcel ships free when it is light or the buyer is a member needs or, because a heavy parcel bought by a member still qualifies.
Python runs a program one line at a time from the top, and an if statement is the first place the path forks. Reaching it, Python evaluates the condition once, using whatever each variable holds at that moment. It runs the block that result selects and then continues below. It never goes back to re-check a condition it has passed, even when a later line changes the variable.
A full trace
The program below buys an item, tries to buy a second, and then resets the balance. Before you play it, write down what you expect each print to show. The second if reads balance after the first block changed it, and the final assignment to 200 comes too late to affect either decision.
1balance = 802price = 5034if balance >= price:5 balance = balance - price6 print("Purchased, balance:", balance)78if balance >= price:9 print("Second purchase ok")10else:11 print("Not enough for a second")1213balance = 20014print("Final balance:", balance)
The second condition reads the balance left after the first block ran.
| Line | What Python does | balance after |
|---|---|---|
| `balance = 80` | stores 80 | 80 |
| `price = 50` | stores 50 | 80 |
| `if balance >= price:` | 80 >= 50 is True, enters the block | 80 |
| `balance = balance - price` | computes 80 - 50 | 30 |
| `print(...)` | prints Purchased, balance: 30 | 30 |
| `if balance >= price:` | 30 >= 50 is False, jumps to else | 30 |
| `print(...)` | prints Not enough for a second | 30 |
| `balance = 200` | stores 200, no condition is re-run | 200 |
| `print(...)` | prints Final balance: 200 | 200 |
Indentation decides what an if owns
Python has no other way to know where a block ends. Each indented line after the header belongs to the if, and the first line back at the margin belongs to the program. Moving a single line left or right by 4 spaces changes which lines the condition controls, as the next 2 programs show. They differ only in the indent of the third print.
With 2 credits, 2 >= 5 is False, so both messages inside the block are skipped and only the credits line prints. The second program is identical except that the unlock message has moved 4 spaces to the left.
Blocks inside blocks
An if block can hold another if. The inner if sits at 4 spaces, inside the outer block, and its own block is indented 8. Each level of nesting adds 4 more spaces, so the depth of the indent tells you how many conditions a line sits under. The inner condition is evaluated only when the outer one was True.
logged_in is True, so Python enters the outer block and prints the dashboard line. It then reaches the inner if, finds is_admin to be False, and skips the admin line. The profile line is indented 4 spaces, so it is back in the outer block and prints. The last line sits at the margin and prints for everyone. Had logged_in been False, Python would have jumped from the outer header straight to that last line, and the inner condition would never have been evaluated.
What does this program print?
When a line that should always run prints only some of the time, look at its indent before its logic. A line indented under an if runs only when the condition is True, so a summary meant for every customer goes at the left margin, after the block ends.
> A merchant on Stripe writes fraud rules that decide what happens to each card charge: a charge from a card already flagged as stolen is blocked before anything else is considered, a charge under 50 dollars from a returning customer is allowed outright, a charge of 50 dollars or more from a returning customer is sent for manual review, and every other charge is also sent for review.
Write conditions, branch on them, and trace exactly which lines Python runs.
- Category
- Python
- Difficulty
- beginner
- Duration
- 37 minutes
- Challenges
- 19 hands-on challenges
Topics covered: The if Statement, Branching with if-else, Chaining if-elif-else, Combining with and/or, Execution Flow
Lesson Sections
- The if Statement (concepts: Conditionals)
What a condition is made of The colon and the indent Watching a True condition Watching a False condition Several if statements in a row
- Branching with if-else (concepts: Conditionals)
A branch can do more than print Exactly one branch, every time
- Chaining if-elif-else (concepts: Conditionals)
Tracing a chain step by step Order decides the answer A chain against separate if statements
- Combining with and/or (concepts: Boolean Operators)
Conditions are values Which operator applies first Putting 3 conditions to work Predict the output of the forecast check below before revealing it. The temperature is 22, it is not raining, and the wind is 35 km/h.
- Execution Flow (concepts: Conditionals)
A full trace The trace table is the tool to reach for whenever a program surprises you. One row per executed line, with the variable values after it, turns a guess into a record you can check against the real output. Lines inside a skipped block get no row at all, because Python never executed them. Indentation decides what an if owns That single move took the unlock message out of the block. It now sits at the margin and prints for every user, including one with 2 credits. The condition is the