Skip to content
C Codeloom
Python

Conditionals in Python: if, elif, else

A practical guide to Python conditionals — if, elif, else, truthiness, conditional expressions, and the patterns that keep branching logic clean and readable.

·7 min read · By Yash Kesharwani
Intermediate 9 min read

What you'll learn

  • How if, elif, and else direct control flow
  • What "truthy" and "falsy" really mean in Python
  • How to combine conditions cleanly
  • When to use a conditional expression instead of a full if/else
  • How to flatten deeply nested branches with early returns

Prerequisites

Conditional statements decide which path your program takes. Almost every non-trivial program has at least one if, and as your programs grow, the way you structure branches is the single biggest lever on readability. This post covers Python’s conditional syntax in full, and then the habits that separate clean branching from a tangle of nested ifs.

The basic if statement

An if statement runs a block of code only when its condition is true:

temperature = 28
if temperature > 25:
    print("It's warm today.")

The indented block runs only if the condition evaluates to True. Python uses indentation — not braces — to define the block. Four spaces is the convention.

If you want a fallback for the false case, add else:

temperature = 12
if temperature > 25:
    print("It's warm today.")
else:
    print("Bring a jacket.")

For more than two outcomes, chain elif (“else if”) branches between them:

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

Python evaluates each condition top to bottom and runs the first block whose condition is true. Everything after is skipped.

Truthy and falsy values

The condition in an if does not have to be a boolean. Python will convert any value to True or False using a simple rule: a handful of values are falsy, and everything else is truthy.

The falsy values are:

  • False
  • None
  • 0, 0.0, 0j
  • Empty containers: "", [], (), {}, set()
  • Custom objects whose __bool__ returns False

Everything else — including non-empty strings, non-zero numbers, and non-empty containers — is truthy.

names = []
if names:
    print("We have names.")
else:
    print("List is empty.")    # this runs

Prefer if names: over if len(names) > 0:. It is shorter, idiomatic, and just as clear once you have internalised the rule.

Combining conditions

Use and, or, and not to combine boolean expressions:

age = 22
has_ticket = True

if age >= 18 and has_ticket:
    print("Welcome in.")

if age < 18 or not has_ticket:
    print("Entry denied.")

A subtle but useful detail: and and or short-circuit. They stop evaluating as soon as the answer is known. This lets you guard against expensive or invalid operations:

data = None
if data is not None and len(data) > 0:
    print(data[0])

If data is not None is false, len(data) is never evaluated — no TypeError.

Python also supports chained comparisons, which read like math:

score = 75
if 70 <= score < 80:
    print("C grade")

This is exactly equivalent to score >= 70 and score < 80 but much easier to read.

Try it yourself. Write a small program that takes a year (e.g. year = 2024) and prints whether it is a leap year. A year is a leap year if it is divisible by 4, except for years divisible by 100, unless they are also divisible by 400.

Conditional expressions

When you want to choose one of two values based on a condition, a full if/else block is overkill. Python has a compact form sometimes called the ternary expression:

age = 17
status = "adult" if age >= 18 else "minor"
print(status)    # minor

Read it as: “use 'adult' if the condition is true, otherwise 'minor'.” It is an expression, not a statement, so it returns a value you can assign or pass to a function.

Use conditional expressions for simple either/or value choices. If either branch needs more than one operation, use a regular if/else.

Comparing against multiple values

When you need to check whether a variable equals one of several values, do not write a long chain of == and or. Use in with a tuple or set:

day = "Saturday"

# Cluttered
if day == "Saturday" or day == "Sunday":
    print("Weekend")

# Clean
if day in ("Saturday", "Sunday"):
    print("Weekend")

For larger groups of values, prefer a set literal — membership checks are constant time:

vowels = {"a", "e", "i", "o", "u"}
letter = "e"
if letter in vowels:
    print("Vowel")

match statements

Python 3.10 introduced match/case for situations where a long elif chain compares the same value:

def describe(status_code):
    match status_code:
        case 200:
            return "OK"
        case 301 | 302:
            return "Redirect"
        case 404:
            return "Not Found"
        case _:
            return "Unknown"

print(describe(302))    # Redirect

case _ is the catch-all. match shines on structured data (tuples, dicts, dataclasses) where it can also unpack patterns — a topic for a later post. For simple integer or string dispatch, a dictionary lookup is often even cleaner; see Python Dictionaries for that pattern.

Avoiding deep nesting

Nested if statements are the most common source of unreadable Python. Two techniques flatten them out.

Early return. Inside a function, check failure cases first and return immediately:

# Nested
def discount(price, member):
    if price > 0:
        if member:
            if price >= 100:
                return price * 0.8
            else:
                return price * 0.9
    return price

# Flat
def discount(price, member):
    if price <= 0:
        return price
    if not member:
        return price
    if price >= 100:
        return price * 0.8
    return price * 0.9

The second version is easier to read because each condition is handled and dismissed before the next one begins.

Combine with and. Two nested checks that share a single outcome become one:

# Before
if user is not None:
    if user.is_active:
        send_email(user)

# After
if user is not None and user.is_active:
    send_email(user)

Try it yourself. Refactor the following nested function to use early returns:

def can_vote(age, citizen, registered):
    if age >= 18:
        if citizen:
            if registered:
                return True
    return False

A worked example

Below is a small ticket-pricing function that uses most of what we have covered: chained elif, in, a chained comparison, and a conditional expression.

def ticket_price(age, day, is_member):
    if day in ("Saturday", "Sunday"):
        base = 20
    else:
        base = 15

    if age < 12:
        base = base * 0.5
    elif 12 <= age < 18:
        base = base * 0.75
    elif age >= 65:
        base = base * 0.7

    final = base * 0.9 if is_member else base
    return round(final, 2)

print(ticket_price(10, "Sunday", False))   # 10.0
print(ticket_price(30, "Monday", True))    # 13.5
print(ticket_price(70, "Saturday", True))  # 12.6

Notice that each step transforms a single base variable. The branches stay shallow because each block decides one thing.

Recap

You now know:

  • if, elif, else direct control flow based on a condition
  • Any value can be used as a condition — Python uses truthy/falsy rules
  • and, or, and not combine conditions, and and/or short-circuit
  • Conditional expressions (x if cond else y) are great for simple value choices
  • Use in to test against several values; prefer a set for large groups
  • match handles structured cases cleanly in Python 3.10+
  • Flatten nested branches with early returns and combined conditions

Next steps

The next post is the natural companion to this one: a closer look at the operators that produce the conditions themselves. We will cover comparison operators, the difference between == and is, and the rules of boolean logic in detail.

→ Next: Comparison and Logical Operators in Python

Questions or feedback? Email codeloomdevv@gmail.com.