Python · Errors and Exceptions
Try Except
The full text of this chapter, to read or revisit. To practise, do the exercises.
▶ Do the exercises
Exercise 1 — What Are Exceptions?
You've already learned about different types of errors like
NameError
,
TypeError
, and
ValueError
. These are called exceptions - errors that occur while your program is running.
Without exception handling, when an error occurs, your program crashes immediately:
# This code will crash codemon_level = int("not a number") # ValueError! print("This line never runs")
But what if we want to handle the error gracefully instead of crashing? That's where try/except comes in - it lets us catch and handle exceptions so our program can continue running.
Think of it like catching a Codémon - instead of letting the error escape and crash your program, you catch it and decide what to do with it!
Syntax Errors vs Exceptions
Remember: Syntax errors (like forgetting a colon) are caught before your program runs. Exceptions (like ValueError) happen while your program is running. You can only catch exceptions with try/except, not syntax errors.
Exercise 2 — Basic try/except Syntax
The basic structure of exception handling uses two keywords:
try
and
except
.
try: # Code that might cause an error risky_code_here() except: # Code that runs if an error occurs handle_error_here()
Here's how it works: 1. Python tries to run the code in the
try
block 2. If an exception occurs, Python stops the try block immediately 3. Python jumps to the
except
block and runs that code instead 4. If no exception occurs, the except block is skipped entirely
Let's see a real example with Codémon levels:
user_input = "twenty" # Try changing to "20" try: codemon_level = int(user_input) print(f"Your Codémon is level {codemon_level}!") except: print("Codemon level is not a valid number! Using default level 1.") codemon_level = 1 print(f"Level set to: {codemon_level}") print("Program continues running!")
Notice that even though an error occurred, the program didn't crash - it handled the error and continued running!
Exercise 3 — When to Use try/except
Which of the following scenarios is the BEST use case for try/except?
Options
• Converting user input to a number, because the input might not be a valid number
• Calculating 2 + 2, because addition might fail
• Printing "Hello", because print statements might not work
• Creating a variable with name = "Aquachu", because assignment might fail
Hint : Think about which operation could actually fail during normal program execution. Use try/except for code that might reasonably cause an exception.
Exercise 4 — Complete the try/except Block
Complete the code to handle the division by zero error. The program should print a message if division fails.
codemon_power = 100 defense = 0 ____: damage = codemon_power / defense print(f"Damage dealt: {damage}") ____: print("Cannot calculate damage - defense is zero!") damage = 0
Options: try except if catch error handle
Hint : Remember the basic structure: try block first, then except block. Think about which keyword starts the risky code and which catches the error.
Exercise 5 — Catching Specific Exceptions
So far we've used
except:
without specifying what type of exception to catch. This catches ALL exceptions without explaining what or why.
There are 2 techniques to improve this: 1. Catch specific exception types 2. Access the actual error message with
as e
Here's the syntax for catching a specific exception type:
try: risky_code() except ValueError: # Only catches ValueError handle_value_error()
Example 1: Catching a specific exception
# Catching ValueError specifically try: codemon_level = int("not a number") except ValueError: print("ValueError caught: Invalid number format!") codemon_level = 1 print(f"Level: {codemon_level}")
Example 2: Accessing the error message with
as e
You can use
as e
to store the exception and see the actual error message:
# Catching any exception with error message try: codemon_level = int("not a number") except Exception as e: print(f"Error type: {type(e).__name__}") print(f"Error message: {e}") codemon_level = 1 print(f"Level: {codemon_level}")
Example 3: Catching a specific exception with
as e
You can combine both: catch a specific exception type AND access its message:
# Catching specific exception with error message try: codemon_level = int("not a number") except ValueError as e: print(f"ValueError caught: {e}") print("Setting default level...") codemon_level = 1 print(f"Level: {codemon_level}")
Why catch exception like this? - More informative error messages - Easier debugging - you know exactly what went wrong - You can handle different errors differently
Common Exception Types
You've already learned about these common exceptions: -
ValueError
: Invalid value (e.g., int("abc")) -
TypeError
: Wrong type (e.g., "hello" + 5) -
ZeroDivisionError
: Division by zero -
IndexError
: Index out of range -
KeyError
: Key not in dictionary -
NameError
: Variable doesn't exist
Exercise 6 — Match Exceptions with Scenarios
Match each code scenario with the exception type it would raise:
Items to match
• int("Aquachu")
• codemon_power / 0
• codemon_list = [1, 2, 3] codemon_list[10]
• "level " + 5
Definitions
• ValueError
• ZeroDivisionError
• IndexError
• TypeError
Exercise 7 — Specific vs General Exception Handling
What is the main advantage of using
except ValueError:
instead of just
except:
?
Options
• It makes debugging easier because you know exactly what type of error occurred
• It makes the code run faster
• It catches more types of errors
• It prevents syntax errors from occurring
Hint : Think about what information you gain when you specify the exact exception type you're catching.
Exercise 8 — Add Specific Exception Types
Complete the code to catch the appropriate specific exception for each scenario.
# Scenario 1: Converting string to int user_input = "Zap" try: level = int(user_input) except ____: print("Invalid number format!") level = 1 # Scenario 2: Dividing by a value power, defense = 10, 0 try: result = power / defense except ____: print("Cannot divide by zero!") result = 0
Options: ValueError ZeroDivisionError TypeError IndexError Exception KeyError
Hint : Think about what type of error each operation would raise. What error do you get when converting an invalid string to int? What about dividing by zero?
Exercise 9 — Multiple except Blocks
You can have multiple
except
blocks to handle different types of exceptions differently:
try: risky_code() except ValueError: # Handle value errors print("Invalid value!") except TypeError: # Handle type errors print("Wrong type!") except: # Handle any other exception print("Something else went wrong!")
Let's see this with a Codémon battle calculator:
def calculate_damage(power, defense, level): try: # This could raise multiple types of errors base_damage = power / defense level_bonus = int(level) * 2 total_damage = base_damage + level_bonus return total_damage except ZeroDivisionError: print("Error: Defense cannot be zero!") return 0 except ValueError: print("Error: Level must be a number!") return 0 except TypeError: print("Error: Invalid data types provided!") return 0 # Test different scenarios print("Test 1 - Normal:", calculate_damage(100, 50, "10")) print("Test 2 - Zero defense:", calculate_damage(100, 0, "10")) print("Test 3 - Invalid level:", calculate_damage(100, 50, "ten"))
Order Matters!
Python checks except blocks from top to bottom and uses the first one that matches. Always put more specific exceptions BEFORE more general ones. If you put a general
except:
first, it will catch everything and the specific ones below will never run!
Exercise 10 — Exception Handler Order
In the following code, which except block will be executed if
int("abc")
raises a ValueError?
try: level = int("abc") except: print("General error") except ValueError: print("Value error") except TypeError: print("Type error")
Options
• The first except block ("General error")
• The second except block ("Value error")
• The third except block ("Type error")
• All three except blocks will execute
Hint : Think about the order in which Python checks except blocks. What happens when a general except: comes before specific exception types?
Exercise 11 — Complete Exception Handling
Complete this Codémon level-up function with proper exception handling. It should handle both ValueError (invalid input) and ZeroDivisionError (when calculating experience rate).
def level_up(current_level, exp_gained, battles_won): ____: new_level = current_level + int(exp_gained) exp_rate = exp_gained / battles_won print(f"Level up! New level: {new_level}") print(f"Experience rate: {exp_rate}") ____ ____: print("Invalid experience value!") new_level = current_level ____ ____: print("Cannot calculate rate - no battles won!") new_level = current_level + int(exp_gained) return new_level # Test the function print(level_up(5, 10, 3))
Options: try except try except ValueError ZeroDivisionError TypeError catch error
Hint : Think about the structure: try block first, then multiple except blocks with specific exception types. Remember which exception happens when converting invalid strings and which happens with division by zero.
Exercise 12 — Codémon Stats Calculator
Build a robust Codémon stats calculator with proper error handling! Create a function called
calculate_stats
that: 1. Takes three parameters: -
name
(string): The Codémon's name -
level
(string): The level as a string -
stats
(dictionary): With keys
"hp"
,
"attack"
,
"defense"
2. Calculates total power:
(attack + defense) * level
3. Calculates efficiency:
total_power / hp
4. Handles these potential errors: -
ValueError
: When level can't be converted to int -
KeyError
: When a required stat is missing from the dictionary -
ZeroDivisionError
: When hp is zero 5. Returns a formatted result string or an error message Test your function with the provided test cases!
Starter code
# Create the calculate_stats function with proper error handling # Parameters: name (str), level (str), stats (dict with 'hp', 'attack', 'defense') # Should handle ValueError, KeyError, and ZeroDivisionError # Test Case 1: Valid data codemon1 = {"hp": 100, "attack": 50, "defense": 40} print("Test 1:", calculate_stats("Aquachu", "10", codemon1)) # Test Case 2: Invalid level (not a number) codemon2 = {"hp": 80, "attack": 60, "defense": 30} print("Test 2:", calculate_stats("Pyrochu", "ten", codemon2)) # Test Case 3: Missing stat in dictionary codemon3 = {"hp": 90, "attack": 45} # 'defense' is missing print("Test 3:", calculate_stats("Florachu", "15", codemon3)) # Test Case 4: Zero HP codemon4 = {"hp": 0, "attack": 70, "defense": 50} print("Test 4:", calculate_stats("Zap", "12", codemon4))
Back to the course