Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 7

Handling Exceptions with Try-Except

Recommended resources

Welcome to the final lesson in our Python Fundamentals module! So far, we've learned to write functions and use modules to build our programs. But what happens when things go wrong? Code doesn't always run perfectly; unexpected situations can arise, like trying to open a file that doesn't exist or dividing a number by zero. If left unhandled, these "errors" will crash your program.

This lesson will teach you how to handle exceptions using try/except blocks. This is a crucial skill for writing robust, reliable software. Instead of letting your program fail, you'll learn to anticipate potential problems and manage them gracefully. This concept is fundamental to your goal of learning FastAPI, as web applications must handle invalid user input and other runtime errors without crashing the server.

Exceptions vs. Syntax Errors

Before we start handling errors, it's important to distinguish between two main kinds of errors in Python.

  1. Syntax Errors: These are errors where the code violates the rules of the Python language itself, like a typo, a missing parenthesis, or incorrect indentation. The Python interpreter detects these before the program even starts running. You've likely seen these before, and the only solution is to fix the code's syntax.

  2. Exceptions: These occur while the program is running, even if the syntax is perfectly correct. The code is valid, but it encounters a situation it cannot handle. For example, asking for user input and trying to convert the text "hello" into an integer will raise a ValueError. These are the errors we can manage with exception handling.

The following article from Real Python provides a clear explanation of this distinction.

Python Exceptions: An Introduction

This article introduces the fundamental difference between syntax errors and exceptions, which is key to understanding what we're trying to "handle."

Read the section "Understanding Exceptions and Syntax Errors". Notice the two examples: the first shows a SyntaxError from an unmatched parenthesis, while the second, print(0/0), shows a ZeroDivisionError exception. This second type is our focus today.


The try and except Block: Your Safety Net

When you anticipate that a line of code might cause an exception, you can wrap it in a try...except block. This acts as a safety net.

  • The code inside the try block is executed first.
  • If an exception occurs within the try block, Python immediately stops executing the rest of the try block and jumps to the except block.
  • The code inside the except block is then executed, allowing you to handle the error gracefully (e.g., by printing a user-friendly message) instead of letting the program crash.
  • If no exception occurs in the try block, the except block is skipped entirely.

Let's see this in action with a very common scenario: trying to open a file that may not exist.

Python Tutorial: Using Try/Except Blocks for Error Handling

This video from Corey Schafer provides an excellent, practical introduction to try/except using a FileNotFoundError.

Watch the first two minutes, from the beginning to the end. Notice how wrapping the open() function call in a try block and adding an except block prevents the program from crashing and allows you to display a custom message.


Be Specific: Catching the Right Exceptions

The simple except: block you just saw will catch any exception. While this seems safe, it's actually a dangerous practice. It can hide bugs you didn't anticipate, making your code difficult to debug. For instance, it might catch a TypeError from a mistake you made elsewhere in the try block, but you'll get the same "file not found" message, leading to confusion.

A much better practice is to specify the exact exception you expect to handle.

You can have multiple except blocks to handle different types of exceptions, and you can also use except Exception as e to catch any remaining, unexpected exceptions and inspect the error message.

Python Exceptions: An Introduction

This Real Python article goes into detail about why catching specific exceptions is critical and how to handle multiple exception types.

Please read the entire section Handling Exceptions. Pay close attention to these key points: The example of catching FileNotFoundError specifically. The ability to access the exception object using as error (or as e). The structure for handling multiple, different except blocks. The strong warning at the end: "Avoid using bare except clauses." This is one of the most important best practices in Python error handling.

This short video clip also demonstrates this concept very clearly, showing how a general exception can hide an unrelated NameError.

Python Tutorial: Using Try/Except Blocks for Error Handling

Corey Schafer continues his explanation by showing why being specific is so important and how to handle multiple exception types correctly.

Watch the segment from this point. He explains why a general Exception is too broad and demonstrates how to stack specific exceptions before a general one. Note the as e syntax to get the actual error message.


The Full Structure: else and finally

The try...except block can be extended with two more optional clauses: else and finally. They give you even finer control over your program's flow.

  • else: The code in the else block runs only if the try block completes successfully (i.e., no exceptions were raised). This is useful for code that should only run when the "risky" part succeeds, like processing a file after you've successfully opened it.

  • finally: The code in the finally block always runs, regardless of what happened in the try, except, or else blocks. It runs if there was an exception, if there wasn't an exception, and even if you exit the block with a return statement. This makes it perfect for cleanup actions, like closing a file or releasing a network connection, ensuring these actions happen no matter what.

This diagram provides a great visual summary of how these four blocks work together.

This flowchart illustrates the execution path for Python's exception handling. The `try` block is always attempted first. If an exception occurs, the `except` block runs. If not, the `else` block runs. The `finally` block runs in either case.

The following video provides a clear walkthrough of both else and finally.

Exception Handling in Python | TRY EXCEPT in Python | Python Tutorial for Beginners #8

This video from techTFQ has distinct sections explaining the else and finally clauses with simple, clear examples.

First, watch the explanation of the else clause from this section. Then, continue with the finally clause from the next part. Notice how finally is executed in both the success and failure scenarios.


Manually Raising Exceptions

Finally, sometimes you need to create an exception yourself. If a function receives invalid input, for example, you can use the raise keyword to signal an error. This allows you to enforce rules in your own functions, which is essential for writing robust and testable code.

def set_age(age):
    if not isinstance(age, int) or age < 0:
        raise ValueError("Age must be a non-negative integer.")
    print(f"Age set to {age}")

try:
    set_age(25)    # This will work
    set_age(-5)    # This will raise a ValueError
except ValueError as e:
    print(f"Error: {e}")

This practice is central to frameworks like FastAPI, which uses raised exceptions to send appropriate HTTP error responses to the client.


Conclusion

You've now reached the end of our Python fundamentals module! In this lesson, we tackled the critical topic of error handling, moving your skills from simply writing code that works to writing code that is resilient and robust.

Key Takeaways:

  • Exceptions are errors that occur during program execution.
  • The try block contains code that might raise an exception.
  • The except block catches and handles specific exceptions, preventing your program from crashing. It's best practice to catch specific exceptions rather than using a bare except:.
  • The else block contains code that runs only if the try block completes without any exceptions.
  • The finally block contains cleanup code that runs no matter what, ensuring that resources are released properly.
  • You can use the raise keyword to trigger exceptions manually when certain conditions are not met.

With this lesson, you've completed the essential Python foundation needed for our journey. You are now prepared to tackle the more advanced concepts that are used directly in FastAPI.

In our next lesson, we will begin a new module, "Advanced Python for FastAPI," starting with a look at type hints. You'll learn how to add type information to your variables and functions, a modern Python feature that FastAPI uses extensively to provide powerful data validation, documentation, and editor support.