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.
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
# 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"))
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.
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
# 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))
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.
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
# 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"))
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.
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
# 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"))
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.
Need a hint?
When two errors deserve the same reply, list them as a tuple in one handler: except (ValueError, ZeroDivisionError).
Show the solution
# 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"))
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.
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
# 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"))
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..
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
# 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.")
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.
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
# 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)
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.
Practice: Type Hints Next: Practice: Files JSON and Paths