Python conditionals — solved exercises with movies, tax brackets, passwords and the number guessing game (and the or that let everybody in)

My first attempt at the movie exercise had this line: if age >= 13 or age < 17:. The idea was “between 13 and 16”. I tested it with my own age, it worked, and I called it done. A few days later I showed it to my 8-year-old cousin so he could play with it, and the program told him he could watch a 13+ movie, no problem. An 8-year-old is “under 17”, and with an or that’s enough. That line is snippet 2 in “What’s wrong here?”, so you can catch it before it catches you.

These are Python conditionals exercises with solutions: four exercises across three levels (basic, intermediate and challenge), three buggy snippets to predict, the solutions commented line by line and a cheat sheet to review before the exam. If you haven’t yet, read the conditionals theory and the practice with three programs first: here I no longer give you the code.

How to use this article

  1. Read the statement and the expected output. The data is fixed in variables at the top of the program, so your output has to match the article’s. Once it works, swap the variables for input().
  2. Try to solve it in VS Code without looking at anything. If you’ve been stuck for more than 10 minutes, read the hint.
  3. Before looking at the solution, test your boundaries: the exact value of each threshold and the one just below it. That’s where conditionals break.
  4. Compare with the commented solution and read “Why it’s done this way”: sometimes your version works and there’s still something to learn from the other one.

Basic level

Exercise 1 — Movie rating system

Write a program that, given the user’s age, a movie’s rating and whether they’re with an adult, says whether they can watch it. The ratings are:

RatingMeaningMinimum age without an adult
GAll audiences0
PGUnder 10 with an adult10
PG-13Not recommended under 1313
RNot recommended under 1717
NC-1718 and over only18

Rules: if they reach the minimum age, they can watch it; if not, but they’re with an adult, they can too, except for NC-17, which allows no exceptions. The rating may come in lowercase ("r"). If it isn’t one of the five, the program says so. With age = 15, rating = "r" and with_adult = False, the expected output is:

--- Result ---
Rating R: not recommended under 17
Your age: 15
Access: ✗ You cannot watch this movie without an adult

First turn the rating into capitals with .upper(). Then, an if/elif chain that only assigns min_age and description. For the final decision you need an or (“old enough or with an adult”) with an and inside it (“with an adult and not NC-17″).

Exercise 2 — Income tax calculator

Write a program that, given the annual gross salary, picks the rate that applies according to these simplified brackets and applies it to the whole salary:

Annual gross salaryRate
Up to 12,450 €19 %
Up to 20,200 €24 %
Up to 35,200 €30 %
Up to 60,000 €37 %
More than 60,000 €45 %

It must show the gross salary, the rate applied, the tax, the annual net salary and the net per month over 12 payments, with two decimals. With salary = 28000.0, the expected output is:

--- Simplified calculation ---
Gross salary: 28000.00 €
Rate applied: 30 %
Tax: 8400.00 €
Net salary: 19600.00 €
Net per month (12 payments): 1633.33 €

These brackets are based on Spain’s income tax (IRPF), but the real tax is progressive: each rate only applies to the part of the salary that falls in its bracket (the first 12,450 € at 19 %, the next part at 24 %…), and there are personal allowances and social security on top. Here a single rate is applied to the whole salary to practise the elif chain. Don’t use this program to work out your taxes.

The brackets say “up to”, so the natural comparison is <=. And with <=, the order is the opposite of the grades one: from the lowest threshold up. If you put salary <= 60000 first, a 28,000 € salary would go in there.

Intermediate level

Exercise 3 — Password strength validator

Write a program that analyses a password against five criteria, says which ones it meets and which it doesn’t, and gives it a score from 0 to 5:

  • At least 8 characters → +1 point.
  • Has capitals → +1 point.
  • Has lowercase letters → +1 point.
  • Has digits → +1 point.
  • Has a special character from !@#$%^&* → +1 point.

Final classification: 0 to 2 points, “Very weak 🔓”; 3, “Weak 🔐”; 4, “Strong 🔒”; 5, “Very strong 🔒”. With password = "Python@2024", the expected output is:

--- Password analysis ---
✓ Long enough (11 characters)
✓ Has capitals
✓ Has lowercase letters
✓ Has digits
✓ Has special characters
Score: 5/5
Strength: Very strong 🔒

any(c.isupper() for c in password) answers “is any character a capital?” (you saw it in the practice with digits). Think carefully about which part of the program is independent checks and which part is a classification with a single result: they aren’t written the same way.

Final challenge

Exercise 4 — Number guessing game

The classic. The program thinks of a number between 1 and 100 and the player tries to guess it. After each attempt, the program says “Too low”, “Too high” or “Correct!”, and at the end it shows how many attempts it took and a rating: 1 to 3, “Incredible 🏆”; 4 to 6, “Great 👏”; 7 to 10, “Good ✓”; more than 10, “Keep practising 💪”.

So your output can be compared, fix secret_number = 69 and keep the guesses in a list, guesses = [50, 75, 63, 69], instead of reading them with input(). The expected output is:

=== GUESS THE NUMBER ===
I'm thinking of a number between 1 and 100...
Attempt 1: 50
→ Too low
Attempt 2: 75
→ Too high
Attempt 3: 63
→ Too low
Attempt 4: 69
→ Correct! 🎉
--- Result ---
You guessed it in 4 attempts
Rating: Great 👏

You need to repeat “get a number and compare it” until it’s right. That’s a while loop, which you’ll see in depth in the next topic; for this exercise while not guessed: is enough, setting guessed = True when the guess is right. The guess for each turn is guesses[attempts] before adding 1 to attempts. In your final version, import random and secret_number = random.randint(1, 100).

What’s wrong here?

Three short snippets, each with a typical bug. Before reading the explanation, predict what each one prints.

Snippet 1: the grade that came from input()

grade = "7"            # input() ALWAYS returns text, even if you type a number

if grade >= 5:
    print("Pass")

Does it print “Pass”? It doesn’t get to print anything:

Traceback (most recent call last):
  File "text.py", line 3, in <module>
    if grade >= 5:
       ^^^^^^^^^^
TypeError: '>=' not supported between instances of 'str' and 'int'

grade is "7", with quotes: it’s a string, just like everything input() returns. And Python has no idea whether the string "7" is greater than or equal to the number 5, so it refuses with a TypeError. Careful: with == there’d be no error ("7" == 7 is simply False), which is worse, because it would fail silently.

Comparing what input() returns directly with a number. Convert it first with int() or float().

The fix is to convert the string before comparing:

grade = "7"
grade = float(grade)    # turns the text into a number before comparing

if grade >= 5:
    print("Pass")

Output:

Pass

The usual way is to convert on the same line you read: grade = float(input("Grade: ")). That way the variable is born a number.

Snippet 2: the age band with or

age = 8

# We want the 13 to 16 age band (can watch PG-13, not R yet)
if age >= 13 or age < 17:
    print("13-16 band: can watch PG-13")
else:
    print("Outside the 13-16 band")

With an 8-year-old, what does it print?

13-16 band: can watch PG-13

It’s my cousin’s or. age >= 13 is False, but age < 17 is True (8 is less than 17), and an or only needs one. In fact, that condition is true for any age: every number is at least 13, or below 17, or both.

Writing a range (“between 13 and 16”) with or. A range is “at least the minimum and below the maximum”: it needs and.

The fix, with a chained comparison:

age = 8

if 13 <= age < 17:             # both at once: 13 <= age and age < 17
    print("13-16 band: can watch PG-13")
else:
    print("Outside the 13-16 band")

Output:

Outside the 13-16 band

To check a range, write the small number first, then the variable, then the big one: 13 <= age < 17. If it sounds like maths when you read it out loud, it’s right.

Snippet 3: the else that went off with another if

It’s an 18+ screening. If the person is an adult, we check whether they have a ticket; if they’re under 18, they can’t come in. With age = 15, what does it print?

age = 15
has_ticket = True

# 18+ screening: the else should be the "under 18" one
if age >= 18:
    if has_ticket:
        print("Can come in to the screening")
    else:                       # which if does this else belong to?
        print("Under 18: cannot come in")
print("End of check")

Real output:

End of check

No “Under 18”, nothing: only “End of check”. The else is indented 4 spaces, level with if has_ticket:, so it’s the else of that inner if, not of the first one. With age = 15, age >= 18 is False and Python skips the whole block, else included. The diagram shows which if each else pairs with in both versions:

Which if each else belongs toOn the left, the else sits at 4 spaces and pairs with if has_ticket; with age 15 the first if is False and nothing but End is printed. On the right, the else at 0 spaces belongs to the first if.Snippet 3: the else indented too farif age >= 18:if has_ticket:print("Can come in…")else:print("Under 18…")print("End…")age = 15 → False: the whole block is skippedOutput: End…Fix: the else under the first ifif age >= 18:if has_ticket:print("Can come in…")else:print("Missing…")else:print("Under 18…")print("End…")Output: Under 18… / End…
An else pairs with the if at its own indentation: 4 spaces tie it to the inner if; 0 spaces, to the outer one.

Deciding which if an else belongs to by how it “should” work. Python decides only by indentation: an else belongs to the if at its own level.

The fix puts the else level with the first if (and, while we’re at it, gives the inner if its own else):

age = 15
has_ticket = True

if age >= 18:
    if has_ticket:
        print("Can come in to the screening")
    else:
        print("Missing a ticket")
else:                           # level with the first if: it is ITS else
    print("Under 18: cannot come in")
print("End of check")

Output:

Under 18: cannot come in
End of check

Commented solutions

Solution exercise 1

# Exercise 1 — Can I watch this movie?
age = 15
rating = "r"                # as the user would type it
with_adult = False

rating = rating.upper()     # "r" → "R": now we only compare capitals

# 1. Minimum age and description of each rating
if rating == "G":
    min_age = 0
    description = "all audiences"
elif rating == "PG":
    min_age = 10
    description = "under 10 with an adult"
elif rating == "PG-13":
    min_age = 13
    description = "not recommended under 13"
elif rating == "R":
    min_age = 17
    description = "not recommended under 17"
elif rating == "NC-17":
    min_age = 18
    description = "18 and over only"
else:
    min_age = -1            # marker for "unknown rating"
    description = ""

print("--- Result ---")
if min_age == -1:
    print(f"Rating {rating} not recognised")
else:
    print(f"Rating {rating}: {description}")
    print(f"Your age: {age}")
    # 2. Gets in if old enough OR with an adult (except NC-17, no exceptions)
    if age >= min_age or (with_adult and rating != "NC-17"):
        print("Access: ✓ You can watch this movie")
    else:
        print("Access: ✗ You cannot watch this movie without an adult")

Output:

--- Result ---
Rating R: not recommended under 17
Your age: 15
Access: ✗ You cannot watch this movie without an adult

Why it’s done this way:

  • .upper() before comparing. That way we only compare with "R", not with "R" and "r". Without it, "r" == "R" is False and the program would say “Rating r not recognised”.
  • The chain only assigns. It’s the FP1 pattern: first min_age and description are decided; then a single access decision that works for every rating. If you put an access print in each branch, you’d have the same condition repeated five times.
  • -1 as the “unknown” marker. No real minimum age is negative, so -1 can’t be confused with a valid rating and the variable exists in every branch (without the else, using min_age later would give a NameError with an odd rating).

The key line, zoomed in:

if age >= min_age or (with_adult and rating != "NC-17"):
PartWith 15, R, no adultValue
age >= min_age15 >= 17False
with_adultFalseFalse
with_adult and rating != "NC-17"False and … (doesn’t look further)False
False or False—False → goes into the else

The brackets aren’t decoration: they group the adult exception. Without them it would work the same (Python evaluates and before or), but with them the rule reads exactly like the statement.

Solution exercise 2

# Exercise 2 — Tax by brackets (simplified version)
salary = 28000.0

# With <= the brackets go from LOWEST to HIGHEST: the first one met is the right one
if salary <= 12450:
    rate = 19
elif salary <= 20200:            # here we already know salary > 12450
    rate = 24
elif salary <= 35200:
    rate = 30
elif salary <= 60000:
    rate = 37
else:
    rate = 45

tax = salary * rate / 100
net = salary - tax
monthly = net / 12

print("--- Simplified calculation ---")
print(f"Gross salary: {salary:.2f} €")
print(f"Rate applied: {rate} %")
print(f"Tax: {tax:.2f} €")
print(f"Net salary: {net:.2f} €")
print(f"Net per month (12 payments): {monthly:.2f} €")

Output:

--- Simplified calculation ---
Gross salary: 28000.00 €
Rate applied: 30 %
Tax: 8400.00 €
Net salary: 19600.00 €
Net per month (12 payments): 1633.33 €

Why it’s done this way:

  • <= and lowest first. 28000 <= 12450 is False; 28000 <= 20200 is False; 28000 <= 35200 is True → 30 %. When we reach each elif we already know the salary is above the previous bracket, so there’s no need to write salary > 12450 and salary <= 20200.
  • The else catches “more than 60,000”. No need to write salary > 60000: if all the previous ones failed, it is.
  • The maths by hand: 28000 × 30 / 100 = 8400; 28000 − 8400 = 19600; 19600 / 12 = 1633.333…, which :.2f prints as 1633.33.
ComparisonResultWhat happens
28000 <= 12450FalseNext
28000 <= 20200FalseNext
28000 <= 35200Truerate = 30 and it leaves the chain
28000 <= 60000Not evaluated—

Copying the grades order (highest first) when you use <=. If salary <= 60000 comes first, every salary up to 60,000 € would pay 37 %.

Solution exercise 3

# Exercise 3 — Password strength validator
password = "Python@2024"
special_chars = "!@#$%^&*"
points = 0

print("--- Password analysis ---")

# Five INDEPENDENT ifs: each criterion adds on its own (with elif only one would count)
if len(password) >= 8:
    print(f"✓ Long enough ({len(password)} characters)")
    points += 1
else:
    print(f"✗ Too short ({len(password)} characters, minimum 8)")

if any(c.isupper() for c in password):        # any capital letter?
    print("✓ Has capitals")
    points += 1
else:
    print("✗ No capitals")

if any(c.islower() for c in password):
    print("✓ Has lowercase letters")
    points += 1
else:
    print("✗ No lowercase letters")

if any(c.isdigit() for c in password):
    print("✓ Has digits")
    points += 1
else:
    print("✗ No digits")

if any(c in special_chars for c in password):     # any character from the list?
    print("✓ Has special characters")
    points += 1
else:
    print("✗ No special characters")

# Now a chain: the score falls into ONE category only
if points <= 2:
    strength = "Very weak 🔓"
elif points == 3:
    strength = "Weak 🔐"
elif points == 4:
    strength = "Strong 🔒"
else:
    strength = "Very strong 🔒"

print(f"Score: {points}/5")
print(f"Strength: {strength}")

Output:

--- Password analysis ---
✓ Long enough (11 characters)
✓ Has capitals
✓ Has lowercase letters
✓ Has digits
✓ Has special characters
Score: 5/5
Strength: Very strong 🔒

Why it’s done this way:

  • Five independent ifs for the criteria. A password can meet several at once, and each one adds its point. With an elif chain, as soon as the first one (length) was met the rest wouldn’t be looked at and "Python@2024" would score 1 point.
  • An elif chain for the classification. Here yes: the score falls into one category only. points <= 2 goes first to catch 0, 1 and 2 at once.
  • len() inside the message. "Python@2024" has 11 characters: P-y-t-h-o-n (6), @ (1) and 2-0-2-4 (4). The program counts them for you instead of you typing the number.
CriterionCheckMet?points after
Length11 >= 8✓1
Capitalsthe P✓2
Lowercasey, t, h…✓3
Digits2, 0, 2, 4✓4
Specialthe @ is in "!@#$%^&*"✓5

Solution exercise 4

# Exercise 4 — Guess the number
# In your version:  import random  and  secret_number = random.randint(1, 100)
secret_number = 69                # fixed here so the output is always the same
guesses = [50, 75, 63, 69]        # what the player would type (in your version, input())

attempts = 0
guessed = False

print("=== GUESS THE NUMBER ===")
print("I'm thinking of a number between 1 and 100...")

while not guessed:                # repeats until guessed (loops: next topic)
    guess = guesses[attempts]     # the guess for this turn
    attempts += 1
    print(f"Attempt {attempts}: {guess}")
    if guess < secret_number:
        print("→ Too low")
    elif guess > secret_number:
        print("→ Too high")
    else:                         # neither lower nor higher: equal
        print("→ Correct! 🎉")
        guessed = True

print("--- Result ---")
print(f"You guessed it in {attempts} attempts")
if attempts <= 3:
    valoracion = "Incredible 🏆"
elif attempts <= 6:               # 4, 5 or 6: the elif already knows it is above 3
    valoracion = "Great 👏"
elif attempts <= 10:
    valoracion = "Good ✓"
else:
    valoracion = "Keep practising 💪"
print(f"Rating: {valoracion}")

Output:

=== GUESS THE NUMBER ===
I'm thinking of a number between 1 and 100...
Attempt 1: 50
→ Too low
Attempt 2: 75
→ Too high
Attempt 3: 63
→ Too low
Attempt 4: 69
→ Correct! 🎉
--- Result ---
You guessed it in 4 attempts
Rating: Great 👏

Why it’s done this way:

  • A three-way if/elif/else inside the loop. Each guess is lower than, higher than or equal to the secret: three mutually exclusive cases, so it’s a chain. The else doesn’t need to say guess == secret_number: if it’s neither lower nor higher, it’s equal.
  • guesses[attempts] before attempts += 1. On the first turn attempts is 0, and guesses[0] is the first guess. If you added first, you’d start at guesses[1] and skip the 50.
  • The rating with <= in increasing order. “4 to 6” doesn’t need attempts >= 4 and attempts <= 6: if it reaches elif attempts <= 6, we already know it isn’t <= 3.

The heart of the program, zoomed in:

while not guessed:                # repeats until guessed (loops: next topic)
    guess = guesses[attempts]     # the guess for this turn
    attempts += 1
    print(f"Attempt {attempts}: {guess}")
    if guess < secret_number:
        print("→ Too low")
    elif guess > secret_number:
        print("→ Too high")
    else:                         # neither lower nor higher: equal
        print("→ Correct! 🎉")
        guessed = True

Turn by turn:

Turnguesses[attempts]attempts afterComparison that matchesMessageguessed
1guesses[0] = 50150 < 69Too lowFalse
2guesses[1] = 75275 > 69Too highFalse
3guesses[2] = 63363 < 69Too lowFalse
4guesses[3] = 694none → elseCorrect!True → leaves

After the loop, 4 <= 3 is False and 4 <= 6 is True: “Great 👏”. The diagram shows what each hint does: cut down the range of possible numbers until only one is left.

How the range narrows in Guess the numberFour rows, one per attempt: 50 is low and 51 to 100 remain; 75 is high and 51 to 74 remain; 63 is low and 64 to 74 remain; 69 is correct.50too lowleft 51-10075too highleft 51-7463too lowleft 64-7469correct!691255075100
Each if/elif/else hint discards part of the line: in four guesses the range goes from 100 numbers to just one.

The strategy of the sample guesses (start at 50 and split the range in half) is called binary search. With it you never need more than 7 attempts for a number from 1 to 100, because each hint throws away half.


Exam-style quiz

Now test yourself as in the exam. The FP1 quizzes look like this: 15 questions in 20 minutes (16 in 30 in the Sequences one), almost all single choice (each wrong answer subtracts a third of what the question is worth) and many «what does this code print?», with the odd fill in the gaps, matching or true or false. Here are 13 original questions on conditionals. Answer without running anything, press Check and read the explanation for each one. These questions are also the question bank for the FP1 theory mock exam, which will mix them with those from the other topics.

Question 1Short answer

What does this program print? Write the exact output.

grade = 6.5
if grade >= 9:
    print("Excellent")
elif grade >= 7:
    print("Good")
elif grade >= 5:
    print("Pass")
else:
    print("Fail")
Solution

Answer: Pass

The conditions are checked from top to bottom and only the first that holds is run. 6.5 does not reach 9 or 7, but it does reach 5: Pass.

Question 2Single choice

How does Python know which instructions are inside an if?

  1. By the indentation (the spaces at the start of the line)
  2. By the braces { }
  3. By the word end at the end
  4. By the brackets around the condition
Solution

Answer: By the indentation (the spaces at the start of the line)

In Python indentation is part of the syntax: the colon : opens the block and everything indented further belongs to it. If you mix indentations, you get IndentationError.

Question 3Short answer

What does this program print? Write the exact output.

x = 15
c = 0
if x > 10:
    c = c + 1
if x > 12:
    c = c + 1
if x > 20:
    c = c + 1
print(c)
Solution

Answer: 2

These are three independent ifs (not elif), so all three are checked: 15 > 10 yes, 15 > 12 yes, 15 > 20 no. c ends up as 2. With elif it would only have added once.

Question 4Single choice

What does this code print?

age = 17
if age >= 18:
    print("Can vote")
print("End")
  1. Only End
  2. Can vote and End
  3. Nothing
  4. An error
Solution

Answer: Only End

Indentation decides: print("End") is at the same level as the if, so it does not depend on the condition. Since 17 ≥ 18 is false, only End is printed.

Question 5Single choice

Which is the right way to check that n is between 1 and 10 (both included)?

  1. 1 <= n <= 10
  2. 1 <= n or n <= 10
  3. n >= 1 and <= 10
  4. n in 1..10
Solution

Answer: 1 <= n <= 10

1 <= n <= 10 is the same as 1 <= n and n <= 10. With or the range is useless: every number is ≥ 1 or ≤ 10.

Question 6True or false

About if, elif and else:

  1. An if can have no else.
  2. An else can have its own condition: else x > 3:.
  3. There can be as many elifs as you need.
  4. If several conditions in an if/elif chain hold, all those blocks are run.
Solution
  • T — An if can have no else.
  • F — An else can have its own condition: else x > 3:.
  • T — There can be as many elifs as you need.
  • F — If several conditions in an if/elif chain hold, all those blocks are run.

else has no condition: it means «in any other case». In an if/elif/else chain only one block runs, the one of the first true condition.

Question 7Single choice

What does this code print?

t = ""
if t:
    print("has text")
else:
    print("empty")
  1. empty
  2. has text
  3. An error, because t is not a boolean
  4. Nothing
Solution

Answer: empty

In an if, 0, 0.0, the empty text '', the empty list [] and None count as false. Everything else is true. That is why if t: means «if t has something».

Question 8Short answer

What does this program print? Write the exact output.

a, b = 4, 9
if a > b:
    m = a
else:
    m = b
if m % 2 == 0:
    print(m // 2)
else:
    print(m * 2)
Solution

Answer: 18

The first if keeps the larger one: m = 9. Since 9 is odd (9 % 2 = 1), it goes to the else: 9 × 2 = 18.

Question 9Fill in the gaps

Complete so that it says whether a number is positive, negative or zero:

if n > 0: prints «positive»; ____ n < 0: prints «negative»; ____: prints «zero».

Words:

  • elif
  • if
  • while
  • else
Solution

if n > 0: prints «positive»; elif n < 0: prints «negative»; else: prints «zero».

If you used another if instead of the elif, it would work, but the else would only belong to that second if. With elif the three options form a single chain.

Question 10Single choice

What does the conditional expression r = 'even' if n % 2 == 0 else 'odd' do?

  1. It stores 'even' or 'odd' in r depending on n
  2. It is an error: the if cannot go on the right of =
  3. It always stores 'even'
  4. It prints even or odd
Solution

Answer: It stores 'even' or 'odd' in r depending on n

The form is value_if_true if condition else value_if_false. It is handy for short assignments; with more than two cases, a normal if/elif is clearer.

Question 11Single choice

What does this code print?

x = 7
if x > 5:
    if x > 10:
        print("A")
    else:
        print("B")
else:
    print("C")
  1. B
  2. A
  3. C
  4. B and C
Solution

Answer: B

It is a nested if: indentation tells you which if each else belongs to. The else of print("B") belongs to if x > 10, and the one of print("C") to if x > 5.

Question 12Order

Put the lines in order to classify a temperature t (over 30 hot, over 15 mild, otherwise cold):

  1. print('cold')
  2. else:
  3. elif t > 15:
  4. print('hot')
  5. print('mild')
  6. if t > 30:
Solution

Correct order:

  1. if t > 30:
  2. print('hot')
  3. elif t > 15:
  4. print('mild')
  5. else:
  6. print('cold')

The order of the conditions matters: if you put t > 15 first, a temperature of 35 would say «mild» and never reach «hot». Always start with the most restrictive case.

Question 13Single choice

What is the value of c at the end?

a, b = 50, 25
c = 0
if a > b and b > 30:
    c = 1
elif a > b or b > 30:
    c = 2
print(c)
  1. 2
  2. 1
  3. 0
  4. 3
Solution

Answer: 2

a > b and b > 30 is True and False = False. a > b or b > 30 is True or False = True, so c = 2.

Watch it step by step in Python Tutor

Snippet 3 is the hardest one to see just by reading, so watch it live. On pythontutor.com, choose Python 3 and paste this program, which has both versions one after the other (A with the badly indented else and B fixed):

age = 15
has_ticket = True

# A: the else is indented inside the inner if
if age >= 18:
    if has_ticket:
        print("A: can come in")
    else:
        print("A: under 18")

# B: the else level with the first if
if age >= 18:
    if has_ticket:
        print("B: can come in")
    else:
        print("B: missing a ticket")
else:
    print("B: under 18")

The real output is a single line:

B: under 18

What to watch step by step:

  1. At the first if age >= 18: (version A), the arrow jumps straight to the version B comment: with age = 15, the whole A block, else included, is skipped.
  2. Notice that in version A no print is ever reached: that’s why no line with “A:” comes out.
  3. In version B, the arrow goes from if age >= 18: to the else: near the end, because that else is level with the first if.
  4. Change age to 20 and has_ticket to False: now version A prints “A: under 18” to an adult (the wrong message in the wrong branch) and B prints “B: missing a ticket”.

Cheat sheet: Python conditionals

The essentials in 30 seconds

  • if / elif / else: colon at the end and 4 spaces of indentation in the block.
  • In a chain, only the first block whose condition is True runs.
  • With >=, thresholds highest first; with <=, lowest first.
  • Independent checks → several ifs. Exclusive cases → elif.
  • Ranges with and or chained: 0 <= grade <= 10. Never x == "a" or "b".
  • Zero and empty are False; everything else, True ("0" too).
  • An else belongs to the if at its own level.

I want to…

I want to…CodeResult
Do something only if it holdsif grade < 5: print("Review")With 4.0 it prints; with 7.5, nothing
Choose between twoif grade >= 5: … else: …One of the two always runs
Choose between severalif … elif … elif … elseOnly the first True
Check a rangeif 0 <= grade <= 10:With 12 → False
Accept “s” and “S”if answer.lower() == "s":"S" → True
See if a list has anythingif submissions:[] → False
Pick a value in one line"Pass" if grade >= 5 else "Fail"With 6.0 → "Pass"
See if a string contains somethingif "@" in email:True or False
Avoid dividing by zeroif n > 0 and total / n >= 5:With n = 0 it doesn’t divide

Templates from the exercises

Classify by brackets (exercises 2 and 3, the FP1 pattern):

if value <= bracket_1:        # with <=, lowest first
    result = "A"
elif value <= bracket_2:      # we already know value > bracket_1
    result = "B"
else:                         # everything left
    result = "C"

With exercise 2, value = 28000 falls into the <= 35200 bracket and gives 30 %.

Count independent criteria (exercise 3):

points = 0
if criterion_1:               # each if adds on its own
    points += 1
if criterion_2:
    points += 1

With "Python@2024", all five criteria add up and points reaches 5.

Decide with an exception (exercise 1):

if age >= min_age or (with_adult and rating != "NC-17"):
    print("Can watch it")
else:
    print("Cannot watch it")

With 15, R and no adult: False or False → “Cannot watch it”.

Symptom and likely cause

SymptomLikely cause
SyntaxError: expected ':'Missing colon at the end of the if, elif or else
SyntaxError: invalid syntax. Maybe you meant '=='…You wrote = instead of == in the condition
IndentationError: expected an indented blockThe line below the if isn’t indented
TypeError: '>=' not supported between instances of 'str' and 'int'You’re comparing a string (from input()) with a number: int() or float() is missing
A high grade comes out “Pass”The elifs with >= go from lowest to highest
The condition always gets inx == "a" or "b", or a range written with or
Nothing is printedAn else indented inside the wrong if, or no branch matches and there’s no else
NameError when using a variable after the ifSome branch doesn’t assign it (the else is missing)
A menu always says “invalid option”You’re comparing input() text with a number (option == 1)

Before handing it in, ask yourself

  1. Have I tested each threshold with its exact value and with the one just below?
  2. Are my checks independent (several ifs) or exclusive (elif)?
  3. Is each side of my ands and ors a complete comparison?
  4. Is every variable I use after the chain assigned in every branch?

With conditionals mastered, the next step is repeating decisions without copying code: Python loops. And if anything in this article was hard going, go back to the theory, the practice or one step further back, to Python operators.

Keep goingAll Python articles

Did this article help you? Here is how you can support SergioLearns →

Sigue aprendiendo

Leave a Reply

Your email address will not be published. Required fields are marked *