Skip to content

Practice: Error Handling and Debugging

View practice code on GitHub Get the Video Course

From the lesson

Practice problems for Section 09 Concepts. Build each yourself first, then expand the solution to check.

Four practice problems, one per concept step; the numbers line up. You build one function, order_cost, and make it safer step by step (the same way the lesson grows calculate_books_per_student). Build each yourself, then check python-practice/solutions. Some end with a short input() "Write a Program" exercise.

These problems build one connected story: you are running the checkout for an online store and learning to handle bad orders without crashing, a missing product, an invalid quantity, an out-of-stock item, and a bad price input.

Step-01: try / except Basics

Concepts: try / except, input().

Problem-1:

Write a function order_cost that takes a total price and a number of units, turns both into whole numbers, and returns the cost of each unit. Wrap the risky lines in a try/except so a bad value returns Could not price this order. instead of crashing. Call it with "100" and "4", then "abc" and "4" (a missing product with no real price), then "100" and "0" (an out-of-stock item with no units), printing each result.

Expected output
25.0
Could not price this order.
Could not price this order.
Need a hint?

Put the two int() conversions and the / division inside one try; a single except Exception returning the message covers both a bad int() (ValueError) and zero units (ZeroDivisionError).

Show the solution
s09_practice01_sol_try_except_basics.py
# Problem-1 Task-1: define order_cost with try/except
def order_cost(total_price, units):
    try:
        price = int(total_price)
        units_count = int(units)
        return price / units_count
    except Exception:
        return "Could not price this order."
# Problem-1 Task-2: print result for valid order
print(order_cost("100", "4"))
# Problem-1 Task-3: print result for bad price
print(order_cost("abc", "4"))
# Problem-1 Task-4: print result for zero units
print(order_cost("100", "0"))

View the full solution file on GitHub

Problem-2 (Write a Program):

Write a program that asks the user for a total price and a number of units, passes them to order_cost, and prints Cost per unit: followed by the cost of each unit.

Example run
Total price: 100
Number of units: 4
Cost per unit: 25.0
Need a hint?

input() always hands back a str, so pass the raw strings straight to order_cost and let its int() calls do the converting.

Show the solution
s09_practice01_sol_try_except_basics.py
# Problem-2 Task-1: read total price from user
total_in = input("Total price: ")
# Problem-2 Task-2: read number of units from user
units_in = input("Number of units: ")
# Problem-2 Task-3: print cost per unit
print("Cost per unit:", order_cost(total_in, units_in))

View the full solution file on GitHub

Pages for this step: Concept | Practice | Workshop

Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions

Step-02: Catching Specific Errors

Concepts: catching a SPECIFIC error; else on success; catching two errors in one except (A, B).

Problem-1:

Reuse order_cost, but catch the two problems separately: if the price is not a whole number (a bad price input) catch the ValueError and return Prices must be whole numbers.; if the item is out of stock with zero units catch the ZeroDivisionError and return There must be at least one unit in stock. Call it with "100" and "4", "abc" and "4", then "100" and "0", printing each result.

Expected output
25.0
Prices must be whole numbers.
There must be at least one unit in stock.
Need a hint?

Order the handlers specific-first: except ValueError for non-whole values, then except ZeroDivisionError for zero units, each returning its own message.

Show the solution
s09_practice02_sol_specific_errors.py
# Problem-1 Task-1: order_cost catching ValueError and ZeroDivisionError separately
def order_cost(total_price, units):
    try:
        price = int(total_price)
        units_count = int(units)
        return price / units_count
    except ValueError:
        return "Prices must be whole numbers."
    except ZeroDivisionError:
        return "There must be at least one unit in stock."
# Problem-1 Task-2: print result for valid order
print(order_cost("100", "4"))
# Problem-1 Task-3: print result for bad price
print(order_cost("abc", "4"))
# Problem-1 Task-4: print result for zero units
print(order_cost("100", "0"))

View the full solution file on GitHub

Problem-2:

Reuse order_cost and add an else block that runs only when the pricing worked: print Order priced. and then return the cost of each unit. Call it with "100" and "4", then with "abc" and "4", printing each result.

Expected output
Order priced.
25.0
Prices must be whole numbers.
Need a hint?

The else block runs only when the try raised nothing, so store the per-unit cost in a variable inside try and return it from else after printing Order priced..

Show the solution
s09_practice02_sol_specific_errors.py
# Problem-2 Task-1: order_cost with an else block on success
def order_cost(total_price, units):
    try:
        price = int(total_price)
        units_count = int(units)
        per_unit = price / units_count
    except ValueError:
        return "Prices must be whole numbers."
    except ZeroDivisionError:
        return "There must be at least one unit in stock."
    else:
        print("Order priced.")
        return per_unit
# Problem-2 Task-2: print result for valid order
print(order_cost("100", "4"))
# Problem-2 Task-3: print result for bad price
print(order_cost("abc", "4"))

View the full solution file on GitHub

Problem-3:

Reuse order_cost, but when both problems deserve the same reply, catch them together with except (ValueError, ZeroDivisionError) and return Please enter a valid order. Call it with "abc" and "4", then with "100" and "0", printing each result.

Expected output
Please enter a valid order.
Please enter a valid order.
Need a hint?

When two errors deserve the same reply, list them as a tuple in one handler: except (ValueError, ZeroDivisionError).

Show the solution
s09_practice02_sol_specific_errors.py
# Problem-3 Task-1: order_cost catching both errors together
def order_cost(total_price, units):
    try:
        price = int(total_price)
        units_count = int(units)
        return price / units_count
    except (ValueError, ZeroDivisionError):
        return "Please enter a valid order."
# Problem-3 Task-2: print result for bad price
print(order_cost("abc", "4"))
# Problem-3 Task-3: print result for zero units
print(order_cost("100", "0"))

View the full solution file on GitHub

Pages for this step: Concept | Practice | Workshop

Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions

Step-03: finally - Cleanup That Always Runs

Concepts: finally always runs.

Reuse order_cost with a combined except that returns Please enter a valid order., and add a finally block that always prints Order closed. Call it with "100" and "4", then with "100" and "0", printing each result.

Expected output
Order closed.
25.0
Order closed.
Please enter a valid order.

finally runs even when you return

A finally block runs no matter what, even when the try block already hit a return. That is why Order closed. prints before the returned value is printed by the caller.

Need a hint?

A finally block runs no matter what, even after a return, so Order closed. prints before the caller prints the returned value.

Show the solution
s09_practice03_sol_finally.py
# Problem-1 Task-1: order_cost with a finally that always runs
def order_cost(total_price, units):
    try:
        price = int(total_price)
        units_count = int(units)
        return price / units_count
    except (ValueError, ZeroDivisionError):
        return "Please enter a valid order."
    finally:
        print("Order closed.")
# Problem-1 Task-2: print result for valid order
print(order_cost("100", "4"))
# Problem-1 Task-3: print result for zero units
print(order_cost("100", "0"))

View the full solution file on GitHub

Pages for this step: Concept | Practice | Workshop

Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions

Step-04: raise - Signal Bad Input on Purpose

Concepts: raise, except ... as err, input().

Problem-1:

Reuse order_cost, turning both inputs into whole numbers, then enforce two rules before dividing: if the price is negative, raise a ValueError with price cannot be negative; if there is less than one unit, raise a ValueError with there must be at least one unit. Otherwise return the cost of each unit. Print the result of calling it with "100" and "4". Then call it with "100" and "0" inside a try/except that catches the error as err, and print Caught a problem: followed by the error. Finally print Still running..

Expected output
25.0
Caught a problem: there must be at least one unit
Still running.
Need a hint?

Here you raise ValueError(...) yourself before dividing; catch it at the call site with except ValueError as err and print err to see the message you raised.

Show the solution
s09_practice04_sol_raise.py
# Problem-1 Task-1: order_cost that raises ValueError on bad rules
def order_cost(total_price, units):
    price = int(total_price)
    units_count = int(units)
    if price < 0:
        raise ValueError("price cannot be negative")
    if units_count < 1:
        raise ValueError("there must be at least one unit")
    return price / units_count
# Problem-1 Task-2: print result for valid order
print(order_cost("100", "4"))
# Problem-1 Task-3: call with zero units and catch the error
try:
    order_cost("100", "0")
except ValueError as err:
    print("Caught a problem:", err)
# Problem-1 Task-4: show the program keeps running
print("Still running.")

View the full solution file on GitHub

Problem-2 (Write a Program):

Write a program that asks the user for a total price and a number of units, passes them to order_cost inside a try/except, and prints Cost per unit: followed by the cost of each unit, or Caught a problem: followed by the caught error.

Example run
Total price: 100
Number of units: 0
Caught a problem: there must be at least one unit
Need a hint?

Wrap the order_cost call in try and catch except ValueError as err, since a raise inside the function travels up to whoever called it.

Show the solution
s09_practice04_sol_raise.py
# Problem-2 Task-1: read total price from user
total_in = input("Total price: ")
# Problem-2 Task-2: read number of units from user
units_in = input("Number of units: ")
# Problem-2 Task-3: price the order and catch any error
try:
    print("Cost per unit:", order_cost(total_in, units_in))
except ValueError as err:
    print("Caught a problem:", err)

View the full solution file on GitHub

Pages for this step: Concept | Practice | Workshop

Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions

Finished this section?

Check your work against the solutions above, then head back to the Section 09 lesson, or try the Section 09 workshop for more reps.

Prefer to learn by watching?

The full video course teaches every concept on screen and builds the projects with you, step by step.

Get the Video Course

Practice: Type Hints Next: Practice: Files JSON and Paths

🎉 New Course
Python for Absolute Beginners
$15.99 $84.99 81% OFF
Get the Video Course