Why this matters
So far, every program has run every line, top to bottom, the same way for every input. Real programs make decisions: reject invalid input, charge shipping only under a certain order total, print an error if a file is missing. The if statement is how a program chooses between paths based on data. It is also where you meet Python's most distinctive feature: indentation defines structure.
The if statement
temperature = int(input())
if temperature > 30:
print("It's hot.")
print("Drink water.")
print("Have a nice day.")
With input 35:
It's hot.
Drink water.
Have a nice day.
With input 20:
Have a nice day.
The anatomy:
ifis followed by a condition, any expression; Python evaluates it and checks whether it is truthy (recall truthiness from the expressions module:0,"",Noneand empty collections are falsy, almost everything else is truthy).- A colon
:ends the header line. - The block (or body) is the indented lines below. They run only if the condition is truthy.
- The first line indented back to the
if's level ends the block.print("Have a nice day.")is not part of theif; it always runs.
Indentation is syntax
In many languages, braces { } mark blocks and indentation is just a courtesy to readers. In Python, the indentation is the block marker. The tokenizer (remember the compile pipeline) turns an increase in indentation into an INDENT token and a decrease into a DEDENT token, and the grammar uses those exactly as other languages use braces.
if temperature > 30: <- header, ends with :
print("It's hot.") <- INDENT: block starts
print("Drink water.") <- same level: same block
print("Have a nice day.") <- DEDENT: block ended
The convention, which you should follow, is 4 spaces per level. Any consistent amount works, but every line in a block must be indented by exactly the same amount. Never mix tabs and spaces; configure your editor to insert spaces when you press Tab.
else: the other path
else gives a block that runs when the condition is falsy. Exactly one of the two blocks runs:
age = int(input())
if age >= 18:
print("adult")
else:
print("minor")
else has no condition of its own, and it lines up with its if.
elif: many paths
For more than two cases, chain conditions with elif (short for "else if"):
n = int(input())
if n > 0:
print("positive")
elif n < 0:
print("negative")
else:
print("zero")
Python tests the conditions in order and runs the block of the first one that is truthy. Once a branch runs, the rest of the chain is skipped entirely; their conditions are not even evaluated. If no condition is true, the else block runs (if there is one; it is optional).
n > 0 ? --yes--> print("positive") ---------------+
| no |
n < 0 ? --yes--> print("negative") ---------------+
| no |
else -------> print("zero") -------------------+
v
continue after chain
Because only the first match runs, order matters when conditions overlap. Grading from high to low lets each test assume the higher ones failed:
score = int(input())
if score >= 90:
grade = "A"
elif score >= 80: # we already know score < 90 here
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(grade)
Reversing the order (testing >= 70 first) would give every passing student a C.
Combining conditions
Conditions can use and, or, not and chained comparisons, all from the expressions module:
x = int(input())
if 1 <= x <= 10:
print("in range")
if x < 0 or x > 100:
print("out of bounds")
if not (x % 2 == 0):
print("odd")
Prefer positive, readable conditions: if x % 2 == 1 reads better than if not (x % 2 == 0).
Nesting
A block can contain any statements, including another if. Each level adds 4 more spaces:
username = input()
password = input()
if username == "ada":
if password == "engine":
print("welcome")
else:
print("wrong password")
else:
print("unknown user")
Nesting is sometimes the clearest structure, but deep nesting is hard to read. Often it can be flattened with and or with elif:
if username != "ada":
print("unknown user")
elif password != "engine":
print("wrong password")
else:
print("welcome")
Both versions behave the same. The second reads as a list of cases, which is easier to scan.
pass: an empty block
A block cannot be empty; Python requires at least one statement. When you need a placeholder, use pass, a statement that does nothing:
if x > 0:
pass # TODO: handle positives
else:
print("not positive")
The conditional expression
When you just need to choose between two values, there is a compact expression form:
age = 20
status = "adult" if age >= 18 else "minor"
print(status)
print(f"{age} is {'even' if age % 2 == 0 else 'odd'}")
adult
20 is even
Read A if condition else B as "A, if the condition holds, otherwise B". It is an expression (it produces a value), so it can go inside an f-string, a function call or an assignment. Use it for simple choices; for anything with side effects or more than two outcomes, a full if statement is clearer.
Common mistakes
Forgetting the colon.
if x > 3
print("big")
File "main.py", line 1
if x > 3
^
SyntaxError: expected ':'
Inconsistent indentation.
if x > 3:
print("big")
print("really big")
File "main.py", line 3
print("really big")
IndentationError: unexpected indent
And a missing indent after a header gives IndentationError: expected an indented block after 'if' statement on line 1.
Using = instead of ==. if x = 3: is a SyntaxError (Python helpfully suggests Maybe you meant '==' or ':=' instead of '='?). = assigns; == compares.
Misreading or. if answer == "y" or "yes": is always true, because it means (answer == "y") or ("yes"), and the non-empty string "yes" is truthy. Write if answer == "y" or answer == "yes":, or if answer in ("y", "yes"):.
Overlapping conditions in the wrong order. As in the grade example, a broad condition placed first swallows the cases meant for later branches.
Recap
if condition:runs its indented block only when the condition is truthy;elifadds more conditions;elsecatches everything left.- In an
if/elif/elsechain, exactly one block runs at most: the first whose condition is true. - Indentation defines blocks; use 4 spaces and be consistent. Python turns indentation changes into INDENT and DEDENT tokens.
passis an empty statement for placeholder blocks.A if condition else Bis an expression that picks one of two values.
Going further: run import dis; dis.dis("if x > 0:\n y = 1\nelse:\n y = 2") and find the POP_JUMP_IF_FALSE instruction: at bytecode level, an if is a comparison followed by a conditional jump over the block.