PyComplete Python Course
Intermediate 45 min

Module 15 β€” Error & Exception Handling

Anticipating what can go wrong, and failing gracefully instead of crashing.

Prerequisite: Module 14 β€” Object-Oriented Programming

After this lesson, you will be able to

  • Catch and handle errors with try/except
  • Use else and finally correctly alongside try/except
  • Raise your own exceptions with raise
  • Recognize common built-in error types

Concept & Syntax

An exception is Python's way of saying "something went wrong, and I don't know how to continue." Without handling, an exception crashes your whole program. try/except lets you anticipate specific failures β€” bad user input, a missing file, a network timeout β€” and respond sensibly instead of crashing.

Syntax
try:
    risky_code()
except SomeError as e:
    handle_it(e)
else:
    only_if_no_error()
finally:
    always_runs()

Examples

Basic try/except Very Easy

Basic try/except
try:
    age = int("not a number")
except ValueError:
    print("That wasn't a valid number.")
OutputThat wasn't a valid number.

Instead of crashing, the program catches the ValueError and responds with a helpful message.

Catching the error object Easy

Catching the error object
try:
    result = 10 / 0
except ZeroDivisionError as e:
    print("Error:", e)
OutputError: division by zero

as e captures the exception object itself, letting you inspect or log its message.

else and finally Intermediate

else and finally
try:
    number = int("42")
except ValueError:
    print("Invalid input")
else:
    print("Conversion succeeded:", number)
finally:
    print("Done attempting conversion.")
OutputConversion succeeded: 42 Done attempting conversion.

else runs only if no exception occurred; finally always runs, whether or not there was an error β€” useful for cleanup.

Raising your own exception Real World

Raising your own exception
def withdraw(balance, amount):
    if amount > balance:
        raise ValueError("Insufficient funds")
    return balance - amount
 
try:
    withdraw(50, 100)
except ValueError as e:
    print("Transaction failed:", e)
OutputTransaction failed: Insufficient funds

raise lets your own code trigger an exception deliberately, with a message explaining what went wrong.

Custom exception classes Challenge

Custom exception classes
class InsufficientFundsError(Exception):
    pass
 
def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFundsError(f"Tried to withdraw {amount}, only {balance} available")
    return balance - amount
 
try:
    withdraw(50, 100)
except InsufficientFundsError as e:
    print(e)
OutputTried to withdraw 100, only 50 available

A custom exception (a class inheriting from Exception) lets calling code catch your specific error type by name, not just a generic one.

Visual Explanation

Python executes code normallyAn error condition occursAn exception object is raisedThe nearest matching except block catches itProgram continues running (instead of crashing)
How Python handles an exception, step by step.
πŸ’‘ Why does this work?

Read the concept explanation above again slowly, line by line β€” every keyword there maps directly onto a line of code in the examples. If it still doesn't click, re-run the traced example (if this lesson has one) one step at a time.

πŸ” What happens internally? (advanced)

Under the hood, Python compiles your source into bytecode and runs it on a virtual machine (the CPython interpreter). Variables are names in a namespace dictionary pointing at objects in memory β€” which is exactly what the memory panel in the tracer above is showing you.

Common Mistakes

βœ— Common mistake 1

A bare `except:` catches everything, including typos and unrelated bugs, hiding problems instead of fixing them.

βœ— Avoid this
This raises not a crash, but real bugs go silently unnoticed
try:
    do_something()
except:
    pass
βœ“ Better approach
Fixed
try:
    do_something()
except ValueError as e:
    print("Invalid value:", e)
βœ“ Best practices
  • Catch the most specific exception type you can β€” ValueError, not a bare except.
  • Never silently swallow an exception with a bare `pass` β€” at least log it.
  • Use finally for cleanup that must happen regardless of success (closing a file, releasing a resource).
  • Raise a clear, specific error message so whoever catches it understands what went wrong.

Exercise & Challenge

Exercise 1 β€” Debug this code

Given this code
try:
    print(10 / 0)
except ValueError:
    print("Cannot divide")

This code should catch a division-by-zero error, but the except clause catches the wrong exception type. What should it say instead of ValueError?

πŸ† Challenge

Write a function safe_divide(a, b) that returns the division result, or prints a friendly message and returns None if b is zero.

  • Use try/except ZeroDivisionError
  • Return the computed value on success
  • Return None and print a message on failure
πŸ’‘ Need a hint?

return None explicitly makes the failure case clear.

πŸ” Show a sample solution
Python
def safe_divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        print("Cannot divide by zero.")
        return None
 
print(safe_divide(10, 2))
print(safe_divide(10, 0))

Quiz

Answer every question, then submit to see your score and explanations.

1. What does a bare `except:` (with no error type) catch?

Nothing
Only ValueError
Every kind of exception, including ones you didn't anticipate
Only syntax errors
A bare except catches everything, which can hide real bugs β€” always prefer a specific exception type.

2. When does the else block of a try/except run?

Always
Only if an exception was raised
Only if no exception was raised
Never, it's not valid syntax
else in a try statement runs only when the try block succeeds with no exception.

3. When does finally run?

Only on success
Only on failure
Always, regardless of success or failure
Never
finally always runs, making it ideal for cleanup code.

4. What does raise ValueError("message") do?

Prints a warning and continues
Deliberately triggers an exception with that message
Logs an error to a file
Ignores the current line
raise deliberately triggers an exception of the given type, with an optional message.

Summary

  • try/except catches exceptions so your program can respond instead of crashing.
  • else runs only on success; finally always runs, ideal for cleanup.
  • raise lets your own code deliberately trigger an exception with a clear message.
  • Always catch the most specific exception type you reasonably can.

Related lessons

Saved privately in your browser β€” no account needed.