Now that you've learned the core mechanisms for handling errors in Python, try
, except
, else
, and finally
, along with raise
, it's time to put these concepts into practice. Writing robust code means anticipating potential issues and handling them gracefully. These exercises will help you solidify your understanding and apply error handling techniques to common programming scenarios.
Remember, the goal isn't just to prevent your program from crashing, but also to provide informative feedback or take corrective action when things don't go as planned.
Often, you need to get numeric input from a user. However, users might enter text, symbols, or nothing at all, which would cause a ValueError
if you try to convert the input directly to an integer or float.
Task: Write a script that asks the user to enter their age. Use a try...except
block to handle the ValueError
that occurs if the input cannot be converted to an integer. If the input is invalid, print an informative message. If the input is valid, print a message confirming their age.
Steps:
input()
function.try
block to attempt converting the input to an integer using int()
.try
block, after the conversion, print the confirmation message.except ValueError
block to catch the specific error if the conversion fails.except
block, print an error message explaining that valid integer input is required.Example Interaction:
Please enter your age: thirty
Error: Please enter a valid whole number for your age.
Please enter your age: 25
Thank you. Your age is 25.
Solution:
user_input = input("Please enter your age: ")
try:
age = int(user_input)
# This line only runs if the conversion above was successful
print(f"Thank you. Your age is {age}.")
except ValueError:
# This block runs if int() raises a ValueError
print("Error: Please enter a valid whole number for your age.")
Explanation: This simple structure is fundamental. We try the operation that might fail (int(user_input)
). If it succeeds, the rest of the try
block executes. If it fails specifically with a ValueError
(because the input wasn't a valid integer string), the code jumps to the except ValueError
block.
Interacting with the file system is another common source of exceptions. Files might be missing, or you might not have permission to read them.
Task: Write a function read_file_content(filename)
that takes a filename as an argument. The function should attempt to open and read the contents of the file. It should handle a FileNotFoundError
by printing a specific message. It should also include a finally
block to print a message indicating that the file reading attempt is finished, regardless of whether it succeeded or failed.
Steps:
read_file_content
that accepts filename
.try
block to open the file in read mode ('r'
) using a with
statement (which handles closing automatically).try
block, read the file's content and print it.except FileNotFoundError
block to print a message like "Error: The file '{filename}' was not found."finally
block that prints "Finished attempting to read file."Example Usage:
# Assume 'my_data.txt' exists and contains "Hello Python!"
read_file_content('my_data.txt')
# Assume 'non_existent_file.txt' does not exist
read_file_content('non_existent_file.txt')
Expected Output:
Hello Python!
Finished attempting to read file.
Error: The file 'non_existent_file.txt' was not found.
Finished attempting to read file.
Solution:
def read_file_content(filename):
"""
Attempts to read and print the content of a file.
Handles FileNotFoundError and ensures a final message is printed.
"""
try:
# Using 'with' ensures the file is closed automatically
with open(filename, 'r') as file:
content = file.read()
print("File content:")
print(content)
except FileNotFoundError:
print(f"Error: The file '{filename}' was not found.")
except Exception as e:
# Catch other potential I/O errors (optional but good practice)
print(f"An unexpected error occurred: {e}")
finally:
# This block always executes
print(f"Finished attempting to read '{filename}'.")
# Example calls
print("--- Reading existing file ---")
# Create a dummy file first for testing
with open('my_data.txt', 'w') as f:
f.write("Hello Python!")
read_file_content('my_data.txt')
print("\n--- Reading non-existent file ---")
read_file_content('non_existent_file.txt')
# Clean up the dummy file (optional)
import os
if os.path.exists('my_data.txt'):
os.remove('my_data.txt')
Explanation: The with open(...)
statement is preferred for file handling as it automatically closes the file, even if errors occur. The try
block contains the file operations. FileNotFoundError
is caught specifically. The finally
block guarantees that the "Finished attempting..." message appears, which can be useful for logging or confirming that the operation was attempted. We also added a general except Exception
to catch other potential issues, though FileNotFoundError
is the most common one here.
else
Let's combine handling multiple specific errors with the else
block.
Task: Create a function divide_numbers(numerator, denominator)
that attempts to perform division. It should:
ZeroDivisionError
if the denominator is zero.TypeError
if either input is not a number (e.g., a string).else
block to print the result only if the division is successful.None
if an error occurs.Steps:
divide_numbers(numerator, denominator)
.try
block to calculate result = numerator / denominator
.except ZeroDivisionError
block to print "Error: Cannot divide by zero."except TypeError
block to print "Error: Both inputs must be numbers."else
block that prints the result (e.g., f"The result is {result}"
) and returns the result
.None
if any exception occurs (this happens implicitly if the except
blocks don't have a return
statement).Example Usage:
divide_numbers(10, 2)
divide_numbers(10, 0)
divide_numbers(10, 'a')
Expected Output:
The result is 5.0
Error: Cannot divide by zero.
Error: Both inputs must be numbers.
Solution:
def divide_numbers(numerator, denominator):
"""
Divides two numbers, handling ZeroDivisionError and TypeError.
Prints the result only on success using the else block.
Returns the result or None if an error occurs.
"""
try:
result = numerator / denominator
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
return None # Explicitly return None on error
except TypeError:
print("Error: Both inputs must be numbers.")
return None # Explicitly return None on error
else:
# This block runs ONLY if the try block completes without errors
print(f"The result is {result}")
return result
# Example calls
print("--- Valid division ---")
divide_numbers(10, 2)
print("\n--- Division by zero ---")
divide_numbers(10, 0)
print("\n--- Invalid input type ---")
divide_numbers(10, 'a')
Explanation: This demonstrates handling multiple, specific errors. The else
block is significant here; it guarantees that the success message and the return result
statement are executed only when the division in the try
block completes without raising any of the caught exceptions.
Sometimes, you need to signal an error condition based on your program's logic, even if Python wouldn't automatically raise an exception.
Task: Write a function calculate_area(length, width)
that calculates the area of a rectangle. Add a check at the beginning: if either length
or width
is less than or equal to zero, raise a ValueError
with the message "Dimensions must be positive". Otherwise, calculate and return the area. Then, write code that calls this function within a try...except
block to handle the potential ValueError
.
Steps:
calculate_area(length, width)
.if
statement to check if length <= 0
or width <= 0
.raise ValueError("Dimensions must be positive")
statement.area = length * width
and return it.calculate_area
with valid inputs (e.g., 5, 10) inside a try
block and print the result.calculate_area
with an invalid input (e.g., 5, -2) inside another try
block.except ValueError as e
block to catch the exception raised by your function and print the error message contained in e
.Example Usage:
# Call with valid dimensions
# Call with invalid dimensions
Expected Output:
Area: 50
Error calculating area: Dimensions must be positive
Solution:
def calculate_area(length, width):
"""
Calculates the area of a rectangle.
Raises ValueError if dimensions are non-positive.
"""
if length <= 0 or width <= 0:
# Raise an exception to signal an invalid state
raise ValueError("Dimensions must be positive")
# This code only runs if the 'if' condition was false
area = length * width
return area
# --- Calling the function and handling potential errors ---
print("--- Calculating with valid dimensions ---")
try:
valid_area = calculate_area(5, 10)
print(f"Area: {valid_area}")
except ValueError as e:
print(f"Error calculating area: {e}")
print("\n--- Calculating with invalid dimensions ---")
try:
invalid_area = calculate_area(5, -2)
# This print won't be reached if an exception is raised
print(f"Area: {invalid_area}")
except ValueError as e:
# Catch the specific error raised by the function
print(f"Error calculating area: {e}")
Explanation: Here, the calculate_area
function enforces a rule (positive dimensions) using raise
. This signals a problem to the code calling the function. The calling code then uses try...except
to catch this specific ValueError
and handle it appropriately, preventing the program from crashing and informing the user about the issue. Raising exceptions is a clean way to handle violations of function preconditions or other logical errors.
These exercises cover the primary ways you'll use exception handling in Python. By practicing catching specific errors, using else
and finally
, and even raising your own exceptions, you can write more reliable and user-friendly programs.
© 2025 ApX Machine Learning