Codeskill

Learn to code, step by step

Error Handling in Python: Managing the Unexpected

How to catch exceptions, respond cleanly, and keep your program running when something goes wrong.

Types of errors

Python has two broad categories:

  • Syntax errors: the code breaks Python’s parsing rules and will not run at all.
  • Exceptions: the syntax is fine, but something fails at runtime – wrong type, missing file, division by zero, and so on.

The try-except block

Wrap risky code in try. If an exception is raised, the matching except block runs instead of crashing:

try:
    # Code that might cause an exception
    result = 10 / 0
except ZeroDivisionError:
    # Code that runs if the exception occurs
    print("You can't divide by zero!")

Handling multiple exceptions

Add separate except blocks for each error type. Catch specific exceptions rather than a bare except – it keeps your intent clear:

try:
    number = int(input("Enter a number: "))
    result = 10 / number
except ZeroDivisionError:
    print("Division by zero is not allowed.")
except ValueError:
    print("Invalid input. Please enter a number.")

The else clause

else runs only when no exception occurred in the try block:

try:
    number = int(input("Enter a number: "))
except ValueError:
    print("That's not a number!")
else:
    print(f"You entered {number}")

The finally block

finally always runs, whether or not an exception occurred. Use it for cleanup:

try:
    file = open('example.txt')
    data = file.read()
except FileNotFoundError:
    print("The file was not found.")
finally:
    file.close()
    print("File closed.")

Raising exceptions

Sometimes you need to signal a problem yourself with raise:

def calculate_age(birth_year):
    current_year = 2021
    age = current_year - birth_year
    if age < 0:
        raise ValueError("Birth year cannot be in the future")
    return age

try:
    my_age = calculate_age(2025)
except ValueError as err:
    print(err)

Custom exceptions

Subclass Exception to define errors specific to your application:

class NegativeAgeError(Exception):
    """Exception raised for errors in the input birth year."""

    def __init__(self, birth_year, message="Birth year cannot be in the future"):
        self.birth_year = birth_year
        self.message = message
        super().__init__(self.message)

try:
    age = calculate_age(2025)
except NegativeAgeError as e:
    print(f"Error: {e}")

Best practices

  • Be specific: catch named exceptions, not a bare except.
  • Keep try blocks small: easier to see which line failed.
  • Use finally for cleanup: close files, release resources.
  • Custom exceptions for clarity: name errors that match your domain.

The goal is not error-free code – it is code that fails gracefully and tells the user (or you) what went wrong.

PreviousString Manipulation: Playing with Text in Python