Unit 1 · Fundamentals

Lesson · Unit 1 · 8 min read

Conditionals, how programs actually make decisions.

A program without conditionals is a recipe that only knows how to do one thing. With if, elif, and else, it starts to react to its inputs. Here's the syntax, the operators, and the patterns that keep your conditional chains readable as they grow.

Section · 01

The basic shape

Three keywords: if, elif, else. Each line that introduces a block ends in a colon. The block itself is indented (4 spaces is the convention):

balance = 240.00

if balance < 0:
    print("Overdraft.")
elif balance < 100:
    print("Low balance.")
else:
    print("You're fine.")

Python runs the first branch whose condition is True and skips the rest. elifis short for “else if” — you can chain as many as you need. elseis optional and catches everything you didn’t match.

Whitespace is not decorative in Python. The indented lines are part of the if block. If you forget to indent, Python throws a syntax error. If you indent inconsistently (mixing tabs and spaces), Python throws a more confusing syntax error. Pick spaces, pick four, never look back.

Section · 02

Comparison operators

The expressions inside if conditions almost always use comparison operators. Six of them:

x == y    # equal
x != y    # not equal
x <  y    # less than
x <= y    # less than or equal
x >  y    # greater than
x >= y    # greater than or equal

The double == is the most common mistake at first. Single =is assignment (“set x to y”). Double ==is a question (“is x equal to y?”). Python won’t let you assign inside an if, so the mistake fails loudly — but it still happens.

One useful Python-ism: you can chain comparisons:

age = 24
if 18 <= age < 65:        # works exactly like math
    print("Working age.")

# Equivalent to:
if age >= 18 and age < 65:
    print("Working age.")

Section · 03

Combining conditions: and, or, not

Three boolean operators. They’re words in Python, not symbols like in other languages:

a and b      # True only if both are True
a or b       # True if at least one is True
not a        # flips True to False and vice versa

Combine them to build the conditions you actually need:

# Access control: must be logged in AND either admin OR account owner
if is_logged_in and (is_admin or is_account_owner):
    show_settings()

# Form validation: must have a name AND a valid email
if name and "@" in email:
    submit()

# Negation: bail out if the file is missing
if not file_exists:
    return

Use parentheses around or groups inside an andexpression. Even if Python’s precedence rules would give you the right answer, the parentheses save your reviewer from having to think.

Short-circuit evaluation

Python evaluates left to right and stops as soon as the answer is known. False and anythingis False, so Python doesn’t bother evaluating “anything.” This is useful for guarding against errors:

# This is safe even if user is None — Python never evaluates user.is_admin
if user and user.is_admin:
    show_admin_panel()

Section · 04

Truthiness — values that act like True or False

Python lets you use almost any value as a condition, not just True and False. The rule is simple: empty things are falsy, everything else is truthy.

# These are all FALSY (treated like False):
None
False
0           0.0
""          # empty string
[]          # empty list
{}          # empty dict
set()       # empty set

# Everything else is TRUTHY.

This makes some checks very compact:

# Verbose:
if len(cart) > 0:
    checkout(cart)

# Pythonic — empty list is falsy:
if cart:
    checkout(cart)

# Same for strings — empty string is falsy:
if name:
    greet(name)

Use this. It reads better and matches what experienced Python programmers expect. The one gotcha: it doesn’t distinguish between None and other falsy values. If you specifically need to know whether something is None (e.g., “was this argument provided?”), use is None:

def fetch(timeout=None):
    if timeout is None:           # specifically "not provided"
        timeout = 30
    ...

Section · 05

Cleaning up long conditional chains

If you find yourself writing an if/elif chain that’s 8 levels deep, the conditional isn’t the problem — the design is. Two quick refactors:

Early return (the guard clause)

# Nested — hard to follow:
def process(order):
    if order.is_valid:
        if order.is_paid:
            if not order.is_shipped:
                ship(order)

# Flat — read top to bottom:
def process(order):
    if not order.is_valid:
        return
    if not order.is_paid:
        return
    if order.is_shipped:
        return
    ship(order)

Lookup tables for many branches

# Long elif chain:
def discount_for(plan):
    if plan == "free":
        return 0
    elif plan == "starter":
        return 0.10
    elif plan == "pro":
        return 0.25
    elif plan == "enterprise":
        return 0.40
    else:
        return 0

# Dictionary lookup — adds new plans without changing logic:
DISCOUNTS = {"free": 0, "starter": 0.10, "pro": 0.25, "enterprise": 0.40}

def discount_for(plan):
    return DISCOUNTS.get(plan, 0)

When you start seeing the same conditional structure repeat, that’s a sign the data should drive the logic, not the other way around.

Curriculum source

Lesson content is original to YorkSims. Topic structure aligns with Python for Everybody by Dr. Charles R. Severance (py4e.com), licensed under Creative Commons Attribution 3.0 Unported.