What are Errors and Exceptions?
Chapter 1: What are Errors and Exceptions?
Welcome to Lesson 8 of our Python and FastAPI course. In the previous lesson, we learned how to read and write files. But what happens when a file doesn't exist, or when we try to divide a number by zero? Your program would crash. In this chapter, we will learn how to handle these situations gracefully using errors and exceptions.
What is an Error?
An error is a problem that occurs in a program. There are two main types of errors in Python:
- Syntax Errors: These happen when you write code that does not follow Python's grammar rules. For example, forgetting a colon after an
ifstatement. Python will not run your program until you fix these. - Exceptions (Runtime Errors): These happen while the program is running. For example, trying to open a file that does not exist, or dividing by zero. These are the errors we will focus on in this lesson.
Why Do We Need to Handle Exceptions?
Imagine you are building a REST API for a task manager. A user sends a request to delete a task that does not exist. If you do not handle the error, your API will crash and return an ugly error message to the user. By handling exceptions, you can return a friendly message like "Task not found" and keep your API running smoothly.
Common Exceptions in Python
Here are some exceptions you will see often:
ZeroDivisionError: Dividing a number by zero.FileNotFoundError: Trying to open a file that does not exist.ValueError: Passing an invalid value to a function (e.g., converting "abc" to an integer).TypeError: Performing an operation on incompatible types (e.g., adding a string and an integer).IndexError: Accessing an index that is out of range in a list.
How to Handle Exceptions: The try-except Block
Python provides the try and except keywords to handle exceptions. The code that might cause an error goes inside the try block. If an error occurs, the code inside the except block runs.
Practical Code Example: Handling Division by Zero
Let's start with a simple example. We will ask the user for two numbers and divide them.
# Example 1: Basic try-except
try:
numerator = int(input("Enter the numerator: "))
denominator = int(input("Enter the denominator: "))
result = numerator / denominator
print(f"The result is: {result}")
except ZeroDivisionError:
print("Error: You cannot divide by zero.")
except ValueError:
print("Error: Please enter valid numbers.")
Explanation:
- The
tryblock contains the code that might raise an exception. - If the user enters a non-numeric value, a
ValueErroris raised, and the correspondingexceptblock runs. - If the user enters zero as the denominator, a
ZeroDivisionErroris raised. - If no error occurs, the
exceptblocks are skipped.
Using a Generic except Block
Sometimes you want to catch any exception, not just a specific one. You can use a generic except block without specifying the exception type. However, this is not recommended because it hides all errors, making debugging difficult.
# Example 2: Generic except (use with caution)
try:
number = int(input("Enter a number: "))
result = 10 / number
print(f"10 divided by {number} is {result}")
except:
print("An error occurred.")
Note: It is better to catch specific exceptions so you can give meaningful error messages.
The else and finally Clauses
You can add an else block that runs only if no exception occurs, and a finally block that runs no matter what (even if an exception occurs). The finally block is often used for cleanup actions, like closing a file.
# Example 3: Using else and finally
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("The file does not exist.")
else:
print("File read successfully.")
print(content)
finally:
print("This will always execute.")
# Make sure to close the file if it was opened
try:
file.close()
except NameError:
pass # file was never opened
Explanation:
- The
elseblock runs only if no exception was raised in thetryblock. - The
finallyblock runs regardless of whether an exception occurred or not. It is perfect for releasing resources.
Raising Exceptions
Sometimes you want to intentionally raise an exception in your code. You can do this using the raise keyword. This is useful when you want to enforce certain conditions.
# Example 4: Raising an exception
def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative.")
print(f"Age is set to {age}")
try:
set_age(-5)
except ValueError as e:
print(f"Error: {e}")
Explanation:
- We define a function
set_agethat raises aValueErrorif the age is negative. - When we call
set_age(-5), the exception is raised and caught by theexceptblock.
Common Mistakes Beginners Make
- Using a bare except: Catching all exceptions without specifying the type can hide bugs. Always try to catch specific exceptions.
- Forgetting to close resources: If you open a file in the
tryblock and an exception occurs, the file may not be closed. Usefinallyor thewithstatement to ensure proper cleanup. - Not handling exceptions at all: Letting your program crash is never a good idea, especially in a web API.
Practical Callout: Why This Matters for Your API
Real-world application: In your future FastAPI project, you will handle exceptions like "Task not found" or "Invalid input data." By using try-except blocks, you can return proper HTTP error codes (like 404 or 400) instead of crashing the server. This makes your API robust and user-friendly.
Practice Task
Write a Python program that does the following:
- Ask the user to enter a filename.
- Try to open and read the file.
- If the file does not exist, catch the
FileNotFoundErrorand print a friendly message. - If any other error occurs, catch it with a generic
exceptand print "An unexpected error occurred." - Use a
finallyblock to print "Operation completed."
Hint: Use the open() function inside a try block.
Solution Check: After writing your code, test it with a filename that exists (e.g., create a text file) and one that does not exist. Make sure your program handles both cases without crashing.
Loading ratings...