All 24 modules are open from the start — nothing here is
locked, and nothing costs anything. Sign in so your progress, titles and
credentials stay with you, on every device you use.
Free forever, with your Google account. No password, no payment.
The line between a program and a list of instructions
Everything so far ran top to bottom, every line, every time. An
if statement is the first thing that changes that: from here on your
code can look at a value and choose. That single idea is what separates a program
from a recipe, and it is the foundation under every loop, filter and validation
in the rest of this track.
Ready?
1
An if Runs a Block, Sometimes
An if takes a condition — anything that produces
True or False — and runs the lines underneath it
only when that condition holds.
temperature = 31
if temperature > 30:
print("Heat warning")
print("Sessions moved indoors")
print("Schedule published")
Two things are doing the work. The colon at the end of the
if line says "a block follows". The
indentation says which lines are in it — and in Python
that is not a style choice, it is the syntax. Four spaces is the
convention, and every line of the block must use the same amount.
In the example above, the two indented lines belong to the
if. print("Schedule published") is back at the
left margin, so it is outside the block and runs whatever the temperature
is.
Why indentation instead of brackets
Most languages mark a block with braces and then let you indent however
you like, which means the indentation can lie about what the code does.
Python removes the gap by making the indentation be the
structure. The cost is that a stray space is a syntax error. The benefit
is that code which looks right is right.
IndentationError
if x > 3: print("hi")
A colon promised a block and none arrived. Python stops before running anything.
Runs when x > 3
if x > 3: print("hi")
Indented, so it is inside the block.
Quick check
An if block has two indented lines, and a third line sits at the left margin. The condition is False. How many of the three run?
2
else Catches Everything Else
else gives you the other branch: it runs exactly when the
if did not. Between them, one of the two always runs.
if score >= 60:
print("Pass")
else:
print("Fail")
elif — short for "else if" — is how you test a second, third
or fourth condition. Python works down the chain and stops at the
first one that is true, ignoring the rest even if they
would also have matched.
A score of 95 matches the first test and never reaches the others,
which is why the chain does not need 90 > score >= 75
anywhere in it. Each branch may assume everything above it was false.
First match wins
Python stops at the first true test. Later branches are not considered.
One chain, one outcome
However many elifs there are, exactly one branch runs.
else is the safety net
Without one, a value nobody thought about falls through and nothing happens at all.
Separate ifs are different
Two if statements can both run. An if/elif pair cannot.
Quick check
With score = 95 and the grade chain above, which tests does Python actually evaluate?
3
Three Ways a Correct-Looking Chain Goes Wrong
The syntax is easy. These three are what actually cost time.
1. The chain is in the wrong order. Because the first
match wins, a broad test placed above a narrow one swallows it. Written
this way, nobody ever gets an A:
The fix is to order the tests from most specific to least, which for
numeric bands means starting at the top and working down.
2. = where == was meant. Python
protects you here — if score = 60: is a
SyntaxError rather than a silent assignment, which is one
place Python is friendlier than C or JavaScript. Worth recognising the
error message all the same.
3. Comparing to True.if is_active == True: works but says the same thing twice.
if is_active: is the same test, and it is what everyone else
writes. The same goes for the negative: if not is_active:.
Truthiness in a condition
An if does not need a comparison — it accepts any value and
applies the rules from the data types module. 0,
0.0, "", None and empty
collections are false; everything else is true. So
if name: reads as "if there is a name", which is usually
exactly right — but remember it cannot tell None from
"", and sometimes that difference matters.
Quick check
A grade chain tests >= 60 first, then >= 90. What happens to a score of 95?
4
Shapes Experienced Programmers Write
Two patterns come up constantly, and both make code shorter and flatter
without making it cleverer.
The guard. Deal with the impossible case first, on its
own, and let everything after it assume the normal case:
if people == 0:
print("Nobody signed up")
else:
print(total / people)
The alternative is to nest the real work inside a check, which pushes it
further right every time you add one. Flat code is easier to read, and
the guard is how you keep it flat.
The conditional expression. When both branches do the
same thing to a different value, Python has a one-line form:
label = "member" if is_member else "guest"
Read it as the value, then the condition, then the fallback. It is for
choosing a value — if the branches do different work, use a
normal if and keep it readable.
Two conditions, or one?
if signed_in: wrapped around
if not suspended: does exactly what
if signed_in and not suspended: does, in two more lines and
one more level of indentation. Nesting is worth it only when the inner
check genuinely does not make sense unless the outer one passed.
If the nested version has no else anywhere in it, it almost
always wants to be one condition joined by and.
Quick check
When is x = a if cond else b the right thing to write?
0 of 9 completed
Real Python runs right here in your browser — nothing to install, nothing
sent to a server. The interpreter downloads once the first time you press
Run, then stays cached.
01
To do
An if takes a condition and runs the indented lines beneath
it only when that condition is True.
if temperature > 30: print("Heat warning")
The colon says a block follows; the indentation says which lines are in
it. Four spaces, and the same amount on every line of the block.
Your task: print Heat warning only when
temperature is above 30, then print
Schedule published every time. With the temperature at 31,
both lines appear.
your_code.py
PythonCtrl↵ to run
Hint
if temperature > 30: on one line, then print("Heat warning") indented four spaces underneath it. Leave the last line where it is — it is outside the block.
Output
02
To do
else runs exactly when the if did not. Between
the two, one branch always runs — there is no way to fall through both.
if score >= 60: print("Pass") else: print("Fail")
Note that else is on its own line at the same indentation as
the if, with its own colon and its own block.
Your task: print Pass when
score is at or above pass_mark, and
Fail otherwise. With the values given, the output is one
line: Fail.
your_code.py
PythonCtrl↵ to run
Hint
"At or above" is >=, not >. The else needs no condition of its own — it is everything the if did not catch.
Output
03
To do
Python's blocks are made of indentation, so getting it wrong is a syntax
error rather than a style problem. Two different complaints show up:
1
expected an indented block
A colon promised a block and the next line was flush left.
2
unexpected indent
A line is indented with no if, else or other block header above it to belong to.
Your task: this code has one of each. Run it, read the
complaint, fix it, run again. The output should be:
Low stock Reorder raised Done
your_code.py
PythonCtrl↵ to run
Hint
Both print lines belong inside the if, so both need the same four-space indent. The last line stays where it is.
Output
04
To do
elif tests another condition when the ones above it were
false. Python works down the chain and stops at the first
match, so each branch may assume everything above it failed.
if score >= 90: grade = "A" elif score >= 75: grade = "B" else: grade = "F"
Your task: set grade from
score using four bands — A at 90 or above,
B at 75 or above, C at 60 or above, and
F below that. Print it. With the score at 78, the output is
B.
Write it as one chain, not four separate if statements.
your_code.py
PythonCtrl↵ to run
Hint
Start at the highest band and work down. Because the chain stops at the first match, the 75 test does not need an upper bound — anything 90 or over was already caught.
Output
05
To do
Because the first match wins, a broad test placed above a narrow one
swallows it completely. The code below compiles, runs, raises nothing —
and nobody in the history of the program has ever been given an A.
This is the most common bug in conditional code, and it is invisible
until someone checks the output against the spec.
Your task: reorder the chain so the bands work. With
score at 95 the output should be A. Keep all
four branches and all four thresholds.
your_code.py
PythonCtrl↵ to run
Hint
Nothing is wrong with any individual test. Put the narrowest one — the highest threshold — at the top, and work downwards from there.
Output
06
To do
Some values make the rest of the code impossible. A guard
deals with those first, on their own, so everything after it can assume
the normal case.
if people == 0: print("Nobody signed up") else: print(total / people)
Without the guard this raises ZeroDivisionError — a crash,
not a message, and one that reaches the person using the program rather
than the person who wrote it.
Your task: the code below divides before it checks. Run
it, read the error, then guard it so it prints
Nobody signed up instead of crashing. Do not change the two
values.
your_code.py
PythonCtrl↵ to run
Hint
Wrap the division in an else, and put the zero case in the if above it. The average line never runs when people is 0, so the division never happens.
Output
07
To do
A condition does not have to be a comparison. An if takes any
value and applies the truthiness rules: 0, 0.0,
"" and None are false, everything else is true.
So if name: reads as "if there is a name", which is what
experienced Python code writes. Two related habits go with it:
1
Never == True
if is_active == True: says the same thing twice. if is_active: is the same test.
2
not for the negative
if not name: rather than if name == "": — and it catches None as well.
Your task: rewrite both conditions below in the plain
form, without changing what they do. The output stays:
No name given Account is active
your_code.py
PythonCtrl↵ to run
Hint
"if not name:" for the first, and "if is_active:" for the second. Both are the same test written the way everyone else writes it.
Output
08
To do
Every nested if pushes the real work one level further right.
Sometimes that structure is genuine. Often it is two conditions that
wanted an and.
The test is simple: if the inner if has no
else, and the outer one has no other body, the two collapse
into one.
if signed_in: if not suspended: print("Welcome")
Your task: flatten the three levels below into a single
if with one condition. Same output, one level of indentation:
Booking confirmed
your_code.py
PythonCtrl↵ to run
Hint
Join all three with and: signed_in and not suspended and seats_left > 0. Read left to right, it says exactly what the nesting said.
Output
09
To do
When both branches assign to the same name and differ only in the value,
Python has a one-line form:
label = "member" if is_member else "guest"
Read it as: the value, then the condition, then the fallback. It is an
expression, so it produces a value and can go anywhere a value
can — including straight inside an f-string.
It is not a general replacement for if. The moment the two
branches do different work rather than pick different values, the normal
form says so more clearly.
Your task: rewrite the four-line if below as
one conditional expression, and add fee, which is
0 for members and 250 for everyone else. Print
both:
guest 250
your_code.py
PythonCtrl↵ to run
Hint
label = "member" if is_member else "guest" replaces all four lines. The fee follows the same shape: 0 if is_member else 250.
Output
The shipping router
To do
An order reaches the warehouse and something has to decide how it ships and
what that costs. The rules below are the ones the business actually gave
you, in the order they gave them.
The tier, in tier:
OVERSIZE when the weight is over 20kg — whatever else is true
otherwise EXPRESS when express was paid for
otherwise STANDARD
The cost, built up in pieces:
base — 500 when the country is JP, 1800 otherwise
surcharge — 200 for every whole kilo above 2, so 4.2kg is two whole kilos over and costs 400
express_fee — 1000 when express was paid for, 0 when not
free_shipping — True only when the order is worth 10000 or more and express was not paid for
total — the three parts added up, or 0 when shipping is free
The tier is one if/elif/else chain, most specific first. For the surcharge, int(weight_kg - 2) gives the whole kilos over the limit — but a parcel under 2kg would make that negative, so guard it. The rest are conditional expressions or short if/else blocks, and free shipping needs `and not is_express`.