An if statement runs a block of code only when a condition is true. Python adds elif for extra conditions and else for everything left over. The syntax is short — a condition, a colon, an indented block — and almost every beginner error with it comes from one of six specific misunderstandings, all covered below.
The basic shape#
temperature = 28
if temperature > 30:
print("Very hot")
elif temperature > 20:
print("Warm")
elif temperature > 10:
print("Mild")
else:
print("Cold")
Warm
Three rules cover the syntax: the condition ends with a colon, the block underneath is indented, and the indentation is what defines the block. There are no braces and no end keyword.
elif and else are both optional. You can have an if on its own, or an if with a dozen elif branches and no else.
Order matters#
Python checks the conditions from top to bottom and stops at the first one that is true. That makes this version wrong:
score = 95
if score > 50:
grade = "Pass"
elif score > 90: # never reached - 95 already matched above
grade = "Excellent"
Put the most specific condition first:
if score > 90:
grade = "Excellent"
elif score > 50:
grade = "Pass"
else:
grade = "Fail"
Comparison and logical operators#
a == b # equal
a != b # not equal
a < b a > b a <= b a >= b
x in items # membership
x not in items
value is None # identity - use for None, True and False
if age >= 18 and has_ticket:
print("Come in")
if day == "Saturday" or day == "Sunday":
print("Weekend")
if not logged_in:
print("Please sign in")
Python lets you chain comparisons, which reads exactly like the maths:
if 0 <= score <= 100:
print("valid score")
For a list of options, in is much cleaner than a chain of or:
if day in ("Saturday", "Sunday"):
print("Weekend")
What counts as true#
Python accepts any value in a condition, not just True and False. These are all falsy:
False, None, 0, 0.0, "", [], {}, (), set()
Everything else is truthy. That gives you a very readable idiom for “is there anything here”:
names = []
if names:
print("we have names")
else:
print("the list is empty") # this runs
Prefer if names: to if len(names) > 0: — it is shorter and works for strings, dictionaries and sets too.
The six mistakes#
1. A missing colon#
if score > 50
print("pass")
SyntaxError: expected ':'
2. Using = instead of ==#
if score = 100:
SyntaxError: invalid syntax
One equals sign assigns, two compare. Python refuses to let you assign inside a plain if, which is genuinely helpful.
3. Wrong indentation#
if score > 50:
print("pass")
IndentationError: expected an indented block
If the error is TabError: inconsistent use of tabs and spaces, your editor is mixing the two. Set it to insert spaces when you press Tab.
4. Comparing different types#
age = input("Age: ") # this is a string
if age > 18:
print("adult")
TypeError: '>' not supported between instances of 'str' and 'int'
Convert first: age = int(input("Age: ")).
5. Testing a variable against several values incorrectly#
if day == "Saturday" or "Sunday": # always true
Python reads this as (day == "Saturday") or ("Sunday"), and a non-empty string is truthy, so the whole condition is always true. Write if day in ("Saturday", "Sunday"):.
6. Comparing floats with ==#
print(0.1 + 0.2 == 0.3) # False
Binary floating point cannot represent 0.1 exactly. Compare with a tolerance:
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True
Nesting, and how to avoid it#
if user is not None:
if user.is_active:
if user.has_permission:
do_the_thing()
Three levels deep before anything happens. Return early instead:
def handle(user):
if user is None:
return "no user"
if not user.is_active:
return "inactive"
if not user.has_permission:
return "not allowed"
do_the_thing()
return "done"
Each condition is now a single flat check with an obvious outcome, and the interesting code is not buried.
The conditional expression#
When both branches only assign a value, one line is enough:
status = "adult" if age >= 18 else "minor"
# useful inside f-strings
print(f"You have {n} item{'' if n == 1 else 's'}")
Keep it to one condition. Chained versions get hard to read quickly.
match, for many fixed cases#
Python 3.10 added a structural match statement, which suits long chains of equality checks:
match command:
case "start":
run()
case "stop":
halt()
case "status" | "info":
report()
case _:
print("Unknown command")
The _ is the catch-all. For ranges and comparisons, elif is still the right tool.
Questions people ask#
Can I use if without else?
Yes. else is only needed when something must happen in the remaining case.
What is the difference between is and ==?
== asks whether two values are equal; is asks whether they are the same object in memory. Use is only with None, True and False. Using it on numbers or strings appears to work for small values and then fails unpredictably.
How many elif branches are too many?
Once you pass four or five, consider a dictionary that maps values to results, or a match statement. Long chains are hard to scan and easy to get out of order.
Why does my if block run when I expected it not to?
Print the condition itself, not the variable: print(score > 50, type(score)). Nine times out of ten the value is a string that looks like a number.
Where to go next#
- Python for loops explained — conditions inside loops.
- Python while loops — where a condition controls repetition.
- Why is my Python code not working? — the errors above in context.