Python · Errors and Exceptions
Try Except
The full text of this chapter, to read or revisit. To practise, do the exercises.
▶ Do the exercisesExercise 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