Python provides try, except, else, finally, and raise as primary mechanisms for handling errors. Writing reliable code means anticipating potential issues and carefully managing them. These exercises offer practice to 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.Exercise 1: Safe Numeric InputOften, 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:Prompt the user for input using the input() function.Use a try block to attempt converting the input to an integer using int().Inside the try block, after the conversion, print the confirmation message.Add an except ValueError block to catch the specific error if the conversion fails.Inside the 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.Exercise 2: Reading from a File SafelyInteracting 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:Define a function read_file_content that accepts filename.Use a try block to open the file in read mode ('r') using a with statement (which handles closing automatically).Inside the try block, read the file's content and print it.Add an except FileNotFoundError block to print a message like "Error: The file '{filename}' was not found."Add a 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.Exercise 3: Calculator with Multiple Error Types and elseLet'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:Handle ZeroDivisionError if the denominator is zero.Handle TypeError if either input is not a number (e.g., a string).Use an else block to print the result only if the division is successful.Return the result if successful, or None if an error occurs.Steps:Define the function divide_numbers(numerator, denominator).Use a try block to calculate result = numerator / denominator.Add an except ZeroDivisionError block to print "Error: Cannot divide by zero."Add an except TypeError block to print "Error: Both inputs must be numbers."Add an else block that prints the result (e.g., f"The result is {result}") and returns the result.Ensure the function returns 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.Exercise 4: Raising an ExceptionSometimes, 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:Define the function calculate_area(length, width).Inside the function, use an if statement to check if length <= 0 or width <= 0.If the condition is true, use the raise ValueError("Dimensions must be positive") statement.If the condition is false, calculate area = length * width and return it.Outside the function, call calculate_area with valid inputs (e.g., 5, 10) inside a try block and print the result.Call calculate_area with an invalid input (e.g., 5, -2) inside another try block.Add an 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 dimensionsExpected Output:Area: 50 Error calculating area: Dimensions must be positiveSolution: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.