Skip to content

Conditionals

A conditional lets a program make decisions by running a block of code only when a condition is True.

The condition ends with a colon :, and the block is the lines indented underneath it, treated as a single unit.

There are two types of conditional statements:

Statement Example When to use
if / elif / else
if length > 15:
    print("giant")
elif length > 8:
    print("large")
else:
    print("small")
The general-purpose default — ranges, comparisons, or checking unrelated things, so use this unless match is clearly a better fit
match / case
species = "ball"
match species:
    case "ball":
        print("ball python")
    case "burmese":
        print("burmese python")
    case _:
        print("other")
Comparing one value against exact, known possibilities — or splitting a tuple into named pieces while checking its values

If / elif / else

A chain of if, elif, and else:

  1. Checks a series of conditions in order
  2. Runs the indented block under the first one that's True
  3. Then exits the whole chain without checking any conditions below it.

if:

This always comes first, and has a condition. If the condition is True, it runs the block of code indented under it, then exits the chain.

elif:

Short for "else if." Any number of elifs can follow the if (or none) — each has its own condition, but is only checked if every condition above it was False. Python runs the block under the first one that's True, then exits the chain, skipping the rest no matter how many elifs follow.

else:

Optional, and always comes last if present. It has no condition of its own — it's the catch-all that runs only when none of the if/elif conditions above it were True.

length = 12

if length > 10:                    # always starts with the if 
    print("that's a big snake")
elif length > 7:                   # then any number (or none) of elifs
    print("that's a medium snake")
elif length > 4:
    print("that's a small snake")
else:                              # lastly comes one optional else 
    print("that's a tiny snake")
See the decision path this code follows
flowchart TD
    A{"`if length > 10:`"} -->|True| B["`print('big snake')`"]
    A -->|False| C{"`elif length > 7:`"}
    C -->|True| D["`print('medium snake')`"]
    C -->|False| E{"`elif length > 4:`"}
    E -->|True| F["`print('small snake')`"]
    E -->|False| G["`else:`"]
    G --> H["`print('tiny snake')`"]

    B -.-> EXIT(["`done, exits the chain`"])
    D -.->EXIT
    F -.->EXIT
    H -.->EXIT

    linkStyle 0 stroke:#3f6b52,stroke-width:2px
    linkStyle 1 stroke:#a33f3f,stroke-width:2px
    linkStyle 2 stroke:#3f6b52,stroke-width:2px
    linkStyle 3 stroke:#a33f3f,stroke-width:2px
    linkStyle 4 stroke:#3f6b52,stroke-width:2px
    linkStyle 5 stroke:#a33f3f,stroke-width:2px
    linkStyle 6 stroke:#3f6b52,stroke-width:2px
    linkStyle 7 stroke:#3f6b52,stroke-width:2px
    linkStyle 8 stroke:#3f6b52,stroke-width:2px
    linkStyle 9 stroke:#3f6b52,stroke-width:2px
    linkStyle 10 stroke:#3f6b52,stroke-width:2px

Fig. 6a — the if/elif/else decision path

Boolean expressions

A boolean expression is needed for every if/elif.

if [boolean expression]:
    [indented code block that runs if above expression is True]
elif [boolean expression]:
    [indented code block that runs if above expression is True and others above were False]

A boolean expression is a boolean value (True or False) or anything that produces one, and is treated as the condition that must be True in order to run a block of code.

A comparison looks different depending on the type of value being checked, as shown below. All of these comparisons result in a True or False boolean expression.

Comparisons by type

Operator Meaning
== equal to
!= not equal to
> greater than
< less than
>= greater than or equal to
<= less than or equal to
length = 12

if length == 12:             # equal to
    print("exactly 12 ft")

if length != 4:              # not equal
    print("not 4 ft")

if length > 10:              # greater than
    print("long snake")

if length < 20:              # less than
    print("under 20 ft")

if length >= 12:             # greater than or equal to
    print("at least 12 ft")

if length <= 12.5:           # less than or equal to
    print("12.5 ft or shorter")
Operator Meaning
== equal to
!= not equal to
in is a substring
not in is not a substring
> comes after alphabetically
< comes before alphabetically
name = "burmese python"

if name == "burmese python":   # equal to
    print("it's a burmese")

if name != "ball python":      # not equal
    print("not a ball python")

if "python" in name:           # is it a substring
    print("name contains 'python'")

if "anaconda" not in name:     # is it not a substring
    print("name doesn't mention anaconda")

if name > "ball python":       # alphabetical comparison
    print("comes after 'ball python' alphabetically")
Check Meaning
[bool] is the bool True
not [bool] is the bool False

Don't compare booleans with == True or is True — a boolean is already the condition, so just use the value directly (or not the value).

venomous = False

if venomous:                   # is it True — don't write venomous == True
    print("handle with care")

if not venomous:               # is it False — don't write venomous == False
    print("safe to handle")
Operator Meaning
is is None
is not is not None
age = None

if age is None:                # is it None
    print("age not recorded")

if age is not None:            # is it anything else
    print("age was recorded")
Operator Meaning
in value exists in the list
not in value is missing from the list
== same contents, in the same order
!= different contents

Or compare a specific item directly, like species[0] == "ball".

species = ["ball", "burmese", "boa"]
other_species = ["ball", "burmese", "boa"]

if "ball" in species:          # is the value in the list
    print("ball python is in the list")

if "anaconda" not in species:  # is the value missing from the list
    print("anaconda isn't in the list")

if species == other_species:   # is it the same contents, in the same order
    print("both lists match")

if "ball" == species[0]:       # compare a specific item
    print("ball python is the first item")
Operator Meaning
== same contents, even if it's a different object
is the exact same object, not just an equal one
snake = ["ball", "burmese"]
other_snake = ["ball", "burmese"]   # separate list, but equal contents

if snake == other_snake:      # do they contain the same items?
    print("equal contents")

if snake != ["ball"]:         # different contents
    print("not equal to a single-item list")

same_snake = snake                  # another name for `snake`
if snake is same_snake:             # same_snake and snake point to the exact same list
    print("this really is the same list")

if snake is not other_snake:        # it's a different list, even though contents match
    print("but not the same list")
Operator Meaning
in value exists in the tuple
not in value is missing from the tuple
== same contents, in the same order
!= different contents

Or compare a specific item directly, like snake[0] == "ball".

snake = ("ball", "5ft", "not venomous")
other_snake = ("ball", "5ft", "not venomous")

if "ball" in snake:
    print("species ball is in the tuple")

if snake == other_snake:
    print("tuples match")

if "ball" == snake[0]:
    print("ball python is the first item")
Operator Meaning
== same contents, even if it's a different object
is the exact same object, not just an equal one
snake = ("ball", "burmese")
other_snake = ("ball", "burmese")   # separate tuple, but equal contents

if snake == other_snake:      # do they contain the same items?
    print("equal contents")

same_snake = snake                  # another name for `snake`
if snake is same_snake:             # same_snake and snake point to the exact same tuple
    print("this really is the same tuple")

if snake is not other_snake:        # it's a different tuple, even though contents match
    print("but not the same tuple")
Operator Meaning
in key exists
not in key is missing

Or compare a specific value directly, like snake["length"] > 2.

snake = {"species": "ball", "length": 3, "venomous": False}

if "venomous" in snake:        # is it a key
    print("snake dict tracks venomous status")

if "habitat" not in snake:     # is it not a key
    print("snake dict has no habitat key")

if snake["length"] > 2:        # compare a specific value
    print("snake in dict is over 2 ft")

Logical operators

Logical operators not, and, or let a single if combine boolean expressions to create more complex conditions.

not venomous               # not False → True

length > 10 and venomous   # True and False → False

length > 10 or venomous    # True or False → True

A and B here are boolean expressions.

A B not A — flips to the opposite A and BTrue only if both are True A or BTrue if either is True
True True False True True
True False False False True
False True True False True
False False True False False

Order of operations: When several logical operators appear together, Python evaluates not first, then and, then or. Even when parentheses aren't required, they often make the condition much easier to read.

Going further

Nested if

Checks a second condition only after the first is True. An if can contain another if, checked only once the outer condition is already True — each level of nesting adds another decision. If both conditions are simple, combining them with and is usually clearer than nesting.

length = 12
venomous = False
if length > 10:
    if venomous:
        print("big and dangerous")
    else:
        print("big but harmless")    # runs
One-line if

Simple checks can be written in one line. For a single statement, the body can go right on the same line as the condition. Save this for short, simple conditions — a normal multi-line if reads more clearly for anything more involved.

The if-else version is a single expression, not a statement — it evaluates to one value or the other, so it's most useful for a quick assignment or a function argument, not as a stand-in for a full if block. value_if_true if condition else value_if_false reads almost like the English sentence it describes.

if venomous: print("careful")    # single-line if — the colon is still required
"careful" if venomous else "safe"    # "careful" — a compact if/else that evaluates to a value
Run an if/elif/else example

All the examples above, combined into one script:

length = 12

if length > 10:
    print("that's a big snake")
elif length > 7:
    print("that's a medium snake")
elif length > 4:
    print("that's a small snake")
else:
    print("that's a tiny snake")

length = 12

if length == 12:             # equal to
    print("exactly 12 ft")

if length != 4:              # not equal
    print("not 4 ft")

if length > 10:              # greater than
    print("long snake")

if length < 20:              # less than
    print("under 20 ft")

if length >= 12:             # greater than or equal to
    print("at least 12 ft")

if length <= 12.5:           # less than or equal to
    print("12.5 ft or shorter")

name = "burmese python"

if name == "burmese python":   # equal to
    print("it's a burmese")

if name != "ball python":      # not equal
    print("not a ball python")

if "python" in name:           # is it a substring
    print("name contains 'python'")

if "anaconda" not in name:     # is it not a substring
    print("name doesn't mention anaconda")

if name > "ball python":       # alphabetical comparison
    print("comes after 'ball python' alphabetically")

venomous = False

if venomous:                   # is it True
    print("handle with care")

if not venomous:               # is it False
    print("safe to handle")

age = None

if age is None:                # is it None
    print("age not recorded")

if age is not None:            # is it anything else
    print("age was recorded")

species = ["ball", "burmese", "boa"]
other_species = ["ball", "burmese", "boa"]

if "ball" in species:          # is the value in the list
    print("ball python is in the list")

if "anaconda" not in species:  # is the value missing from the list
    print("anaconda isn't in the list")

if species == other_species:   # is it the same contents, in the same order
    print("both lists match")

if "ball" == species[0]:       # compare a specific item
    print("ball python is the first item")

snake = ("ball", "5ft", "not venomous")   # a tuple works the same way

if "ball" in snake:
    print("species ball is in the tuple")

if snake == ("ball", "5ft", "not venomous"):
    print("tuples match")

snake = {"species": "ball", "length": 3, "venomous": False}

if "venomous" in snake:        # is it a key
    print("snake dict tracks venomous status")

if "habitat" not in snake:     # is it not a key
    print("snake dict has no habitat key")

if snake["length"] > 2:        # compare a specific value
    print("snake in dict is over 2 ft")

snake = ["ball", "burmese"]
other_snake = ["ball", "burmese"]   # separate list, but equal contents

if snake == other_snake:      # do they contain the same items?
    print("equal contents")

if snake != ["ball"]:         # different contents
    print("not equal to a single-item list")

snake = ["ball", "burmese"]

same_snake = snake                  # another name for `snake`
if snake is same_snake:             # same_snake and snake point to the exact same list
    print("this really is the same list")

other_snake = ["ball", "burmese"]   # separate list, but equal contents
if snake is not other_snake:        # it's a different list, even though contents match
    print("but not the same list")

length = 12
if length > 15:
    print("giant")
elif length > 8:
    print("large")
elif length > 4:
    print("medium")
else:
    print("small")

length = 3
if length > 15:
    print("giant")
elif length > 8:
    print("large")
elif length > 4:
    print("medium")
else:
    print("small")

venomous = False

if venomous:
    print("handle with care")
else:
    print("safe to handle")

length = 12
venomous = False

if length > 10 and venomous:
    print("big and dangerous")
if length > 10 or venomous:
    print("worth a closer look")
if not venomous:
    print("safe to handle")

if (length > 10 and not venomous) or length > 20:
    print("worth a closer look")

length = 12
venomous = False

if length > 10:
    if venomous:
        print("big and dangerous")
    else:
        print("big but harmless")

venomous = True
if venomous: print("careful")

status = "careful" if venomous else "safe"
print(status)

Match / case

A match statement compares one value against several case options and runs the code for the first matching case.

Both examples below do the same thing, but match is often easier to read than a long if/elif sequence when checking one value against many possibilities.

species = "ball"

# if/elif chain
if species == "ball":
    print("small constrictor")    # runs
elif species == "burmese":
    print("large constrictor")
else:
    print("unknown species")

# the same logic as a match statement
match species:
    case "ball":
        print("small constrictor")    # runs
    case "burmese":
        print("large constrictor")
    case _:
        print("unknown species")
See the decision path this code follows
flowchart TD
    START["`match species:`"] --> A{"`case 'ball':`"}
    A -->|match| B["`print('small constrictor')`"]
    A -->|no match| C{"`case 'burmese':`"}
    C -->|match| D["`print('large constrictor')`"]
    C -->|no match| E["`case _:`"]
    E --> F["`print('unknown species')`"]

    B -.-> EXIT(["`done, exits the chain`"])
    D -.->EXIT
    F -.->EXIT

    linkStyle 1 stroke:#3f6b52,stroke-width:2px
    linkStyle 2 stroke:#a33f3f,stroke-width:2px
    linkStyle 3 stroke:#3f6b52,stroke-width:2px
    linkStyle 4 stroke:#a33f3f,stroke-width:2px
    linkStyle 5 stroke:#3f6b52,stroke-width:2px
    linkStyle 6 stroke:#3f6b52,stroke-width:2px
    linkStyle 7 stroke:#3f6b52,stroke-width:2px
    linkStyle 8 stroke:#3f6b52,stroke-width:2px

Fig. 6b — the match/case decision path

Matching an int

A case can compare any type of value, not just strings.

match length:
    case 3:
        print("hatchling size")
    case _:
        print("not a hatchling")

Match multiple values with |

Lets one case match several possible values using |, so you don't need a separate case for each one.

match species:
    case "ball" | "corn":
        print("small species")     # runs — species is "ball"
    case _:
        print("other")

Default value _

Runs a block of code if no case matched — either discarding the value with _, or capturing it into a variable.

match species:
    case "burmese":
        print("it's a burmese!")
    case _:                             # Option 1:  Unsaved default value
        print("not a burmese")          # value discarded

match species:
    case "burmese":
        print("it's a burmese")
    case n:                             # Option 2: Saved default value
        print(f"{n} is not a burmese")  # stores the value as new variable n

If you want the code to still run a block of code even if no specific case matched, there are two ways to add a default value at the end that will match anything. A default value goes last — without one, a value matching no cases would not run any block of code. Option 1 (_) throws the matched value away; Option 2 (giving it a variable name, like n) saves it so the block can use it.

case + if

Only run the block of code if there's a case match and the if condition is also True. Adding if [condition] after a pattern turns it into a guard — the branch only runs if the pattern matches and the condition is True. If the guard is False, Python moves on to the next case even though the pattern itself matched.

length = 12
match length:
    case n if n > 10:
        print("big")     # runs — 12 > 10
    case n:
        print("small")

Unpacking a tuple

A case can pull a tuple apart into named pieces while also checking its shape or specific values.

snake = (12, "ball")
match snake:
    case (length, "ball"):                      # tuple with 2 items, where second is "ball"
        print(f"a {length} ft ball python")     # in this example, this case will run
    case (length, species):                     # tuple with any 2 items
        print(f"a {length} ft {species} python")
    case (length,):                             # tuple with any 1 item
        print(f"just a length: {length}")
    case _:                                     # 0 items, or tuple with more than 2 items
        print("invalid format")

A match can pick a different case depending on the tuple's length or the value in a specific position, while still unpacking the rest into names — all in one step, as shown above. Compare with regular assignment (length, species = snake), which always unpacks the same way, would crash on a 1- or 3-item tuple, and can't pick a different case based on species.

Going further

Run a match/case example

All the examples above, combined into one script:

species = "ball"

# if/elif chain
if species == "ball":
    print("small constrictor")
elif species == "burmese":
    print("large constrictor")
else:
    print("unknown species")

# the same logic as a match statement
match species:
    case "ball":
        print("small constrictor")
    case "burmese":
        print("large constrictor")
    case _:
        print("unknown species")

length = 3

match length:
    case 3:
        print("hatchling size")
    case _:
        print("not a hatchling")

species = "ball"

match species:
    case "ball" | "corn":
        print("small species")

species = "ball"

match species:
    case "anaconda":
        print("giant")
    case _:
        print("not an anaconda")

species = "ball"

match species:
    case "anaconda":
        print("giant")
    case n:                    # any variable name works here, not just n
        print(f"{n} is not an anaconda or burmese")

snake = (12, "ball")

length, species = snake   # regular assignment — see note above
print(species, length)

match snake:
    case (length, "ball"):                  # 2 items, second is 'ball'
        print(f"a {length} ft ball python")
    case (length, species):                 # 2 items, any other species
        print(f"a {length} ft {species}")
    case (length,):                         # 1 item — comma makes this a 1-tuple pattern
        print(f"just a length: {length}")
    case _:                                 # 0 items, or more than 2
        print("0 items, or more than 2")

length = 12

match length:
    case n if n > 10:
        print("big")
    case n:
        print("small")

Control flow statements

break and continue are loop-control keywords, not conditional ones, but they almost always appear inside a conditional — checking a condition, then stopping the loop early (break) or skipping straight to the next pass (continue). They work the same way whether checked with if/elif or match/case, since neither creates its own loop scope — both just pass straight through to whatever loop contains them. Covered fully, with more examples, on the Loops page.

Break

Exits the loop immediately, skipping everything left in it. Nothing after it runs, and anything left in the sequence (or any remaining passes of the condition) is skipped entirely.

for s in species:
    if s == "ball":
        break
    print(s)                     # burmese  rock

count = 0
while count < 5:
    if count == 3:
        break
    print(count)
    count += 1                   # 0  1  2

for s in species:
    match s:
        case "ball":
            break                 # stops the loop, same as it would inside an if
        case _:
            print(s)

Continue

Skips just the current pass, then keeps looping. The rest of the loop body doesn't run for that item, but the loop itself keeps going from the next item or the next check of the condition.

for s in species:
    if s == "ball":
        continue
    print(s)                     # burmese  rock  blood

count = 0
while count < 5:
    count += 1
    if count == 3:
        continue
    print(count)                 # 1  2  4  5

for s in species:
    match s:
        case "ball":
            continue              # skips just "ball", same as it would inside an if
        case _:
            print(s)

Going further

pass placeholder

Temporarily fill an empty block when you're not ready to write the inside code yet. Python doesn't allow an empty block after a colon. pass does nothing, but acts as a placeholder until you're ready to add code so that the empty block won't cause a syntax error in the meantime — works the same way after if/elif/else and case alike.

if venomous:
    pass    # placeholder — does nothing, but prevents a syntax error

match venomous:
    case True:
        pass    # same idea, inside a case block
Run a control flow example

All the examples above, combined into one script:

species = ["burmese", "rock", "ball", "blood"]

for s in species:
    if s == "ball":
        break
    print(s)

count = 0
while count < 5:
    if count == 3:
        break
    print(count)
    count += 1

for s in species:
    match s:
        case "ball":
            break
        case _:
            print(s)

for s in species:
    if s == "ball":
        continue
    print(s)

count = 0
while count < 5:
    count += 1
    if count == 3:
        continue
    print(count)

for s in species:
    match s:
        case "ball":
            continue
        case _:
            print(s)

venomous = True

if venomous:
    pass

match venomous:
    case True:
        pass

print("checked venomous status, no action taken yet")