← Back to course
Code Crew G6+ / Week 10 / Wednesday
3/6
Week 10 Β· Bugs and tests

Wednesday

Catching errors with try
// Tracebacks, try and except, and assert
⏱ about 30 min

Wednesday: Catching errors with try

Rocket's crew counter asks how many crew are aboard. A visitor types four, in letters, and the whole program stops with a ValueError.

"I cannot stop people from typing words," Rocket says. "But I do not want the program to crash every time they do."

Raven thinks about how she would handle it in person. "What do you notice?" she asks. "If someone gave me a word instead of a number, I would just ask again, politely."

Nova shows a path that splits in two and joins back together. "Would you like a hint?" she asks. "Python can try something risky. If a certain error happens, it runs a different block instead of stopping."

Rocket writes try, and then except ValueError.

try and except

Python runs the try block. If a ValueError happens inside it, Python jumps to the except ValueError block instead of stopping. If no error happens, the except block is skipped.

Name the error you expect. Catching every possible error hides real bugs, so programmers keep the except as narrow as they can.

# ask_number.py
def ask_number(question):
    """Keep asking until the user types a whole number."""
    while True:
        text = input(question)
        try:
            return int(text)
        except ValueError:
            print("Please type a whole number, like 12.")

crew = ask_number("How many crew aboard? ")
print("Crew aboard:", crew)
How many crew aboard? four
Please type a whole number, like 12.
How many crew aboard? 4.5
Please type a whole number, like 12.
How many crew aboard? 4
Crew aboard: 4
FOLLOW THE TRY
  • Read the question.
  • Tap your answer.
The user types 7 straight away. Does the except block run?
How does the loop end?
The user types ten, then 2.0, then 12. How many times is the please message printed?
WHY THIS EXERCISEten and 2.0 both cause a ValueError in int(), and 12 works, so the message appears twice.

Another way to handle the first run

Last week you checked os.path.exists before loading a file. A try and except can do the same job: try to open it, and catch FileNotFoundError.

# load_or_start.py
import json

def load_list(filename):
    """Load a JSON list, or start an empty one."""
    try:
        with open(filename) as f:
            return json.load(f)
    except FileNotFoundError:
        return []

items = load_list("not_made_yet.json")
print("Loaded", len(items), "items")
At your computer
1. Type ask_number.py, save it and run it. Type four, then 4.5, then 4.
2. Change except ValueError to except TypeError. Run it and type four. What happens now, and why?
3. Change it back to ValueError.
4. Type load_or_start.py and run it. Check that it says Loaded 0 items.

Practice: catch a ZeroDivisionError

Any error you expect can be caught. Here, sharing supplies among zero crew would divide by zero, so the function catches that case and returns 0.

# per_person.py
def per_person(supplies, crew):
    """Whole supplies each crew member gets."""
    try:
        return supplies // crew
    except ZeroDivisionError:
        return 0

print(per_person(20, 4))
print(per_person(20, 3))
print(per_person(20, 0))
5
6
0
FOLLOW THE TRY
  • Read the question.
  • Tap your answer.
Why does per_person(20, 3) give 6?
Which call runs the except block?
What would per_person("20", 4) cause?
What does per_person(9, 2) return?
What does per_person(5, 0) return?
Which error does int("abc") raise?
StatementTrue or false?
If no error happens, the except block is skipped.?
except ValueError also catches a ZeroDivisionError.?
A narrow except helps real bugs stay visible.?
try and except can replace every test you write.?
WHY THIS EXERCISEexcept catches only the named error, so other bugs still show up, and tests still matter.

Your programs can now recover from mistakes instead of stopping. Tomorrow you will write tests that check your functions automatically.

← Tuesday