Conditional Statements: if, elif and else

Conditions choose which block runs. Python adds chained comparisons, truthiness and a conditional expression that together remove most of the nesting other languages need.

The if statement

age = 20

if age >= 18:
    print("Adult")
    print("May vote")

print("Always runs")

The colon opens the block and the indentation defines it. Both indented lines belong to the if; the unindented line does not. There are no braces and no then keyword.

if and else

temperature = 15

if temperature > 30:
    print("Hot")
else:
    print("Not hot")

elif

elif is short for "else if". Only the first matching branch runs, and the rest are skipped entirely.

score = 78

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 40:
    grade = "D"
else:
    grade = "F"

print(grade)      # C
Order matters. Because only the first true branch runs, the tests must run from the most specific to the least. Reversing this ladder so it starts with score >= 40 would give every passing student a D.

elif is not the same as several ifs

n = 15

# One branch runs.
if n > 10:
    print("greater than 10")
elif n > 5:
    print("greater than 5")

# BOTH run, because each if is evaluated independently.
if n > 10:
    print("greater than 10")
if n > 5:
    print("greater than 5")

Conditions do not have to be booleans

items = []
name = ""
count = 0

if not items:
    print("no items")

if name:
    print("named")
else:
    print("no name given")

if count:
    print("has a count")     # does not run; 0 is falsy

Any object can be tested. Use this for emptiness, and use is None when absence must be distinguished from zero or empty.

Chained and combined conditions

age = 25
has_licence = True

if 18 <= age < 65:
    print("working age")

if age >= 18 and has_licence:
    print("may drive")

if age < 5 or age > 90:
    print("special rate")

day = "sat"
if day in ("sat", "sun"):        # far better than day == "sat" or day == "sun"
    print("weekend")

Nested conditions, and how to avoid them

# Deeply nested: hard to follow
def process(order):
    if order is not None:
        if order.get("paid"):
            if order.get("items"):
                return "ready to ship"
            else:
                return "no items"
        else:
            return "unpaid"
    else:
        return "no order"
# Guard clauses: each failure exits immediately, the happy path stays flat
def process(order):
    if order is None:
        return "no order"
    if not order.get("paid"):
        return "unpaid"
    if not order.get("items"):
        return "no items"
    return "ready to ship"

The second version says the same thing with no nesting at all. Handling failures first and returning early is the single most effective way to keep Python functions readable.

The conditional expression

age = 20

# Statement form
if age >= 18:
    label = "adult"
else:
    label = "minor"

# Expression form: the whole thing produces a value
label = "adult" if age >= 18 else "minor"

print(f"You are an {label}" if age >= 18 else f"You are a {label}")

# Useful inside a call or a comprehension
scores = [45, 82, 91, 30]
print([("pass" if s >= 50 else "fail") for s in scores])

Keep it to one line and one condition. Nesting conditional expressions inside each other is legal and unreadable; use elif instead.

Matching against many values

With a dictionary

def describe_day(code):
    names = {1: "Monday", 2: "Tuesday", 3: "Wednesday"}
    return names.get(code, "Unknown")


print(describe_day(2))      # Tuesday
print(describe_day(9))      # Unknown

A dictionary lookup replaces a long elif ladder that tests one variable against constants, and it is easier to extend.

With match, from Python 3.10

def handle(command):
    match command.split():
        case ["quit"]:
            return "exiting"
        case ["add", item]:
            return f"adding {item}"
        case ["move", x, y]:
            return f"moving to {x},{y}"
        case _:
            return "unknown command"


print(handle("add pen"))       # adding pen
print(handle("move 3 4"))      # moving to 3,4
print(handle("dance"))         # unknown command

match is structural pattern matching, not a C style switch. It destructures the value as well as comparing it, which is where its real value lies. The final case _ is the catch all.

The pass statement

if some_condition:
    pass              # deliberately do nothing, for now
else:
    handle_it()

A block cannot be empty. pass is the placeholder that keeps the code parseable while you write the rest.

Common mistakes

  • Forgetting the colon at the end of the if, elif or else line.
  • Using = instead of == in a condition. Python raises a SyntaxError, which is helpful.
  • Writing if x == 1 or 2:. The 2 is a separate truthy operand, so the whole condition is always true. Write if x in (1, 2):.
  • Ordering an elif ladder from least specific to most specific.
  • Writing if x == True: instead of if x:.
  • Using truthiness where 0 is valid data and is None was needed.

Best practices

  • Use guard clauses and early returns instead of nesting.
  • Use in with a tuple or a set instead of a chain of or comparisons.
  • Give a complicated condition a name: is_eligible = age >= 18 and has_licence.
  • Replace an elif ladder that maps one value to another with a dictionary.
  • Keep conditional expressions short and standalone.

Practice

  1. Write a grade classifier and then deliberately reverse the ladder order. Explain what breaks.
  2. Rewrite a triple nested validation function using guard clauses.
  3. Write a leap year check using and, or and %, and test 1900, 2000, 2024 and 2025.
  4. Convert an elif ladder that maps month numbers to names into a dictionary lookup.
  5. Explain why if name == "a" or "b": is always true, and rewrite it.

Conclusion

if, elif and else are simple; keeping them readable is the skill. Return early, name your conditions, use in for value sets, and let a dictionary do the work when you are mapping one value to another.

Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Python notes →
Python

The for Loop and range()

A Python for loop walks over the items of a collection directly. range() supplies numbers when you genuinely need a counter, which is less often than...

Read more
Python

The while Loop

while repeats for as long as a condition holds. Use it when the number of repetitions is unknown, and make sure something inside the loop can make the...

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.