If, elif and else in Python: Conditionals Explained

A conditional runs one block of code or another, depending on whether something is true.

age = 20if age >= 18: print("Adult") else: print("Minor")# Adult

Python’s version has three things worth knowing early. There are no braces — indentation defines the block. The middle branch is elif, short for else if. And if x = 5 is a SyntaxError, not a silent bug, which is a deliberate improvement on C.

This guide covers the syntax, truthiness, the ternary operator, and when a chain of elif should be something else.

The short version
Blocks defined byIndentation — no braces anywhere
elif is short forelse if — and there’s no limit to how many
Only the first match runsConditions are checked in order, then it stops
One-line formx if condition else y
if x = 5A SyntaxError, on purpose

The syntax

if condition: # runs when the condition is true else: # runs when it isn't

⚠️ Two things are mandatory: the colon at the end of the line, and the indentation of the block. Python has no braces — the indentation is the block.

Four spaces is the convention, and PEP 8 recommends it. What matters is consistency: mixing tabs and spaces raises TabError.

The else is optional:

if temperature > 30: print("It's hot") # nothing happens otherwise

elif: more than two branches

elif is short for else if, and you can chain as many as you need.

score = 85if score >= 90: grade = "A" elif score >= 80: grade = "B" elif score >= 70: grade = "C" else: grade = "F"print(grade) # B

⚠️ Conditions are checked in order, and it stops at the first match. Once score >= 80 is true, the rest aren’t even evaluated.

That ordering matters more than it looks:

# Wrong order — everything above 70 gets a C if score >= 70: grade = "C" elif score >= 80: grade = "B" # unreachable for any score

A score of 95 matches the first condition and stops there. ⚠️ With overlapping ranges, put the most restrictive condition first.

elif vs several separate ifs

# elif — only one runs if x > 10: print("big") elif x > 5: print("medium")# separate ifs — both can run if x > 10: print("big") if x > 5: print("medium")

With x = 20, the first prints “big” and the second prints both. They’re different constructs, not styles.

⚠️ Truthiness: what counts as true

The eight falsy values in Python — False, zero, empty string, empty collections and None — contrasted with truthy values like the string zero and a list containing zero

A condition doesn’t have to be a comparison. Python evaluates any value as true or false:

if items: # true if the list has anything in it process(items)if name: # true if the string isn't empty greet(name)

These values are false:

False 0 0.0 "" [] {} set() None

Everything else is true — including "0", "False" and [0], because a non-empty string and a non-empty list are true regardless of what’s inside.

The bug this causes

def check(quantity): if not quantity: return "not informed" return quantitycheck(None) # not informed ← correct check(0) # not informed ← WRONG, zero is a real value

⚠️ if not x means “empty or absent”. When you mean specifically absent, test for None:

if quantity is None: return "not informed"

Our guide on None in Python covers the distinction in full.

Comparison operators

== equal != not equal < less than > greater than <= less or equal >= greater or equal in contains is same object

= in a condition is a SyntaxError

if x = 5: # SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

⚠️ Python refuses to compile it, and even suggests the fix. In C this compiles and silently assigns, which is one of the classic sources of bugs in that language — Python removed the possibility entirely.

is compares identity, not value

if value is None: # correct — None is a singleton if name is "Ana": # wrong — compares object identity if name == "Ana": # correct for values

Use is only with None, True and False. For everything else, ==.

Chained comparisons

if 1 < x < 10: # valid Python if x > 1 and x < 10: # same thing, longer

Python allows the mathematical form, and it’s clearer. Most languages don’t.

Comparing floats

0.1 + 0.2 == 0.3 # Falseimport math math.isclose(0.1 + 0.2, 0.3) # True

⚠️ Never compare floats with ==. Binary representation makes the result slightly off, and math.isclose() exists for exactly this.

and, or and not

if age >= 18 and has_id: print("Allowed")if day == "Saturday" or day == "Sunday": print("Weekend")if not logged_in: redirect()

Two behaviours worth knowing.

They short-circuit. In a and b, if a is false, b is never evaluated — which is what makes this safe:

if user is not None and user.is_active: ... # the second check never runs when user is None

And they return a value, not a boolean:

name = user_input or "Anonymous" # uses the default when empty

⚠️ Which carries the falsy trap again: quantity or 10 replaces a legitimate zero with 10.

The ternary operator

A conditional on one line, when both branches are just a value.

status = "adult" if age >= 18 else "minor"# the long form if age >= 18: status = "adult" else: status = "minor"

The order reads oddly at first — value, condition, alternative — but it’s the standard form, and Python has no ? :.

⚠️ Use it only when both branches are a single expression. Nesting ternaries produces lines nobody can read:

g = "A" if s>=90 else "B" if s>=80 else "C" if s>=70 else "F" # don't

Nested conditionals, and how to avoid them

if user is not None: if user.is_active: if user.has_permission: do_something() else: print("No permission") else: print("Inactive") else: print("Not found")

Three levels, and the interesting code is buried at the deepest one. ⚠️ Note there are no braces — the indentation alone defines each level, which is why consistency matters so much in Python.

The guard clause inverts it:

if user is None: return "Not found" if not user.is_active: return "Inactive" if not user.has_permission: return "No permission"do_something() # the happy path, unindented

Handle the failures first and leave early. The main logic ends up at the top level, and each condition is read independently.

When a chain of elif should be something else

Two alternatives for long chains — and neither is a replacement for a simple if.

match/case, for matching a value

match status_code: case 200: return "OK" case 404: return "Not Found" case 500 | 502 | 503: return "Server Error" case _: return "Unknown"

⚠️ Available since Python 3.10 — on older versions it’s a SyntaxError, not a missing feature. Our guide on match/case covers it.

A dictionary, for many options

operations = { "+": lambda a, b: a + b, "-": lambda a, b: a - b, }handler = operations.get(op) if handler is None: raise ValueError(f"Unknown operation: {op}")result = handler(2, 3) # 5

Better when the mapping is data rather than logic, or when it changes at runtime. A fifty-entry dictionary is fine; a fifty-branch elif isn’t.

⚠️ Keep if/elif for ranges and boolean conditions — neither alternative handles score >= 80 well.

if in comprehensions

# Filtering — the if goes at the end evens = [x for x in range(10) if x % 2 == 0]# Choosing a value — the ternary goes at the front labels = ["even" if x % 2 == 0 else "odd" for x in range(5)]

⚠️ The position tells you which one it is. At the end it filters; at the front it’s a ternary choosing between two values. The second form can’t have an if without an else, because every item needs a value.

The walrus operator

if (n := len(items)) > 10: print(f"Too many: {n}")

:= assigns and tests in one expression, available since Python 3.8. It avoids computing something twice when you need both the test and the value.

⚠️ Conditionals on a server

One pattern matters more than the others: failing safely.

# Risky — an unexpected value falls through silently if role == "admin": grant_full_access() elif role == "user": grant_read_access()# Safe — anything unexpected is denied if role == "admin": grant_full_access() elif role == "user": grant_read_access() else: deny()

⚠️ A chain without an else does nothing when nothing matches — and in an access check, “does nothing” can mean the previous state persists. Always close the chain with an else, even if it only logs.

And a second one: don’t confuse absent with empty in configuration.

timeout = os.environ.get("TIMEOUT")if not timeout: # an explicit "0" is also falsy timeout = 30if timeout is None: # only when the variable isn't set timeout = 30

Someone who deliberately set TIMEOUT=0 gets 30 with the first version — the kind of bug that only appears in one environment.

A condition that matches nothing does nothing — silently

An access check with no final else leaves the previous state in place, and nothing in the log says so. Copahost VPS plans give you root access, logs you can actually read, and your choice of Python version. From €3.99/month, with snapshots.

See VPS plans

Frequently asked questions

What does elif mean in Python?

It’s short for else if — a condition checked only when the ones above it were false. You can chain as many as you need, and only the first match runs.

Why does Python use indentation instead of braces?

Because indentation is the block. There are no braces anywhere in the language — the colon opens the block and the indentation defines its extent. ⚠️ Mixing tabs and spaces raises TabError, so pick one; four spaces is the convention.

What happens if I write if x = 5?

A SyntaxError — Python refuses to compile it and suggests == or :=. ⚠️ In C the same line compiles and silently assigns, which is a classic bug source. Python removed the possibility on purpose.

What counts as false in Python?

Eight values: False, 0, 0.0, "", [], {}, set() and None. Everything else is true — including "0" and [0], because a non-empty string or list is true regardless of contents.

What’s the difference between if not x and if x is None?

if not x is true for any falsy value — zero, an empty string, an empty list. if x is None is true only for None. ⚠️ Use the second when absence and emptiness mean different things, which in form data and configuration they usually do.

Should I use is or == to compare?

is compares object identity; == compares value. Use is only with None, True and False — for everything else, ==. Python even warns when you use is with a literal.

Can I check two conditions in one line?

Yes, with and and or — and Python also allows the mathematical form: if 1 < x < 10 is valid and clearer than x > 1 and x < 10. Most languages don’t allow it.

What’s the ternary operator in Python?

value_if_true if condition else value_if_false — a conditional in one line. Python has no ? :. ⚠️ Use it only when both branches are a single expression; nested ternaries are unreadable.

Why is 0.1 + 0.2 == 0.3 false?

Because binary can’t represent those decimals exactly, so the sum is 0.30000000000000004. ⚠️ Never compare floats with == — use math.isclose(), which exists for this.

How do I avoid deeply nested ifs?

With guard clauses: handle the failure cases first and return early, leaving the main logic at the top level. Three nested levels usually become three flat checks followed by the real work.

When should I use match/case instead of elif?

When you’re matching a value against several options, or matching the shape of data. ⚠️ It needs Python 3.10 — on older versions it’s a SyntaxError, not a missing feature. Keep elif for ranges and boolean conditions.

Why does my elif branch never run?

Usually because an earlier condition already covers it. ⚠️ With overlapping ranges, order mattersif score >= 70 before elif score >= 80 means no score ever reaches the second, because 95 matches the first and the chain stops.

Conclusion

Conditionals in Python are simple to write and easy to get subtly wrong — and most of the trouble comes from what counts as true.

Three things carry it. if not x is true for zero, empty strings and empty lists, not just None — so when absence and emptiness differ, test is None. Order matters in an elif chain, because only the first match runs and a broad condition placed first makes the rest unreachable. And if x = 5 is a SyntaxError, which is Python removing one of C’s classic bugs rather than a limitation.

And the one that matters on a server: a chain of elif with no final else does nothing when nothing matches. In an access check, “does nothing” means the previous state stays — and the log has nothing to say about it. Close the chain, even if the else only writes a line.

Share the Post:
Picture of Gustavo Gallas

Gustavo Gallas

Graduated in Computing at PUC-Rio, Brazil. Specialized in IT, networking, systems administration and human and organizational development​. Also have brewing skills.