Exceptions handling in Python

Exceptions Handling

Exceptions Handling

Overview

An exception is an error that occurs during the execution of a program.
Exception handling allows a program to:
Avoid crashes by handling unexpected errors.
Provide user-friendly feedback instead of cryptic error messages.
Ensure proper cleanup (e.g., closing files, releasing resources).
Basic Example

                try:
                    # Code that might raise an exception
                    result = 10 / 0
                except ZeroDivisionError:
                    # Code to handle the specific exception
                    print("Cannot divide by zero!")
            
Note that syntax errors, like print("hello) can not be handled, as they occur in parsing stage, i.e. before the code is executed.

Syntax


            try:
                # Code that may raise an exception
            except ExceptionType:
                # Code to handle the specific exception
            else:
                # Code that should run only if the try block was successful
            finally:
                # Always executes, regardless of whether an exception occurred
                # (useful for cleaning up resources such as closing files or network connections)
        
try block contains code that might raise an exception. If an exception is raised, the program moves to the except block.
except block handles the exception. You can have multiple except blocks to handle different types of exceptions separately (e.g., ZeroDivisionError, FileNotFoundError).
else block is optional and runs only if no exception is raised in the tryblock. It is useful for code that should run when everything goes as expected.
finally block is also optional and runs no matter what, whether or not an exception occurred. It is typically used for cleanup actions, such as closing files or network connections.

Example


                try:
                    # Code which can raise an exception
                    user_number = int(input("Enter a number: "))
                except ValueError:
                    # This block will execute if the user input cannot be converted to an integer
                    # (e.g., if a non-numeric value is entered)
                    print("You did not enter a number!")
                except Exception as e:
                    # This block will execute if any other unexpected error occurs
                    print(f"An unexpected error occurred: {e}")
                else:
                    # This block will execute only if no exception was raised in the try block
                    print("Your number is ", user_number)
                finally:
                    # This block will always execute, regardless of whether an exception occurred or not
                    print("Cleanup...")
            

Common Exception Types

Python has many built-in exception types, including:
ZeroDivisionError: Occurs when dividing by zero
TypeError: Occurs when an operation is performed on an inappropriate data type
ValueError: Occurs when a function receives an argument of the correct type but inappropriate value
FileNotFoundError: Occurs when trying to access a non-existent file
IndexError: Occurs when trying to access an index that is out of range
KeyError: Occurs when a dictionary key is not found
ImportError: Occurs when an import statement fails
Reference: Exception hierarchy @python.org

Catching Multiple Exceptions

You can handle different exceptions with separate except blocks:

                try:
                    number = int(input("Enter a number: "))
                    result = 10 / number
                    print(f"Result: {result}")
                except ValueError:
                    print("That's not a valid number!")
                except ZeroDivisionError:
                    print("Cannot divide by zero!")
                except Exception as e:
                    # This block will execute if any other unexpected error occurs
                    print(f"An unexpected error occurred: {e}")
            

The else Clause

The else clause executes when no exceptions are raised in the try block

                try:
                    number = int(input("Enter a number: "))
                except ValueError:
                    print("That's not a valid number!")
                else:
                    # This runs only if no exceptions occurred
                    print(f"You entered: {number}")
            

The finally Clause

The finally clause executes regardless of whether an exception occurred

                try:
                    # Try to read file
                    file = open("data.txt", "r")
                    content = file.read()
                except FileNotFoundError:
                    print("The file does not exist.")
                finally:
                    # This runs whether an exception occurred or not
                    # Great for cleanup operations
                    file.close() if 'file' in locals() else None
            

Raising Custom Exceptions

Raising Custom Exceptions

The raise statement

You can raise exceptions explicitly using the raise statement:
Raising exceptions can improve code robustness and provide informative feedback to users.
You can pass to raise an ExceptionType to be raised

                def get_user_age():
                    while True:
                        try:
                            age = int(input("Enter your age: "))
                            if age < 0:
                                raise ValueError("Age must be between 1 and 99")
                            return age
                        except ValueError:
                            print("Please enter a valid age.")


                user_age = get_user_age()

                # Continue with your program using the valid age
                print(f"You are {user_age} years old.")

            

Define And Raise Custom Exceptions

We can use the raise statement to trigger custom errors when necessary.
To define a custom exception, create a new class that inherits from the built-in Exception class:

                # define custom exception
                class UserNameError(Exception):
                    """Raised when a username is less than 3 characters long."""

                    def __init__(self, username):
                        super().__init__(
                            f"Username '{username}' is too short (must be at least 3 characters)"
                        )


                try:
                    user_name = input("Enter your name: ")
                    if len(user_name) < 3:
                        raise UserNameError(user_name)
                except UserNameError as e:
                    print(e)
                except Exception as e:
                    print(f"Oops! Something went wrong! ({e})")

                ### Example usage
                # Enter your name: ab
                # Username 'ab' is too short (must be at least 3 characters)
            

Best Practices

Best Practices

Be specific: Catch only the exceptions you expect and can handle
Don't catch all exceptions: Avoid bare except: statements that catch everything
Keep try blocks small: Only include code that might raise exceptions
Handle exceptions appropriately: Don't hide errors without addressing them
Use finally for cleanup: Resource cleanup belongs in finally blocks

Resources

Resources

Blogs, wiki, docs

Errors and Exceptions @The Python Tutorial

Homework

Homework

The tasks are given in next gist file
You can copy it and work directly on it. Just put your code under "### Your code here".

These slides are based on

customised version of

Hakimel's reveal.js

framework