try / except / finally

Updated March 15, 2026 · Keywords
keyword exception error-handling control-flow

The try, except, finally statements in Python handle exceptions—unexpected events that disrupt normal program flow. They let you catch errors, handle them gracefully, and ensure cleanup code always runs.

Syntax

try:
    # Code that might raise an exception
    risky_operation()
except SomeError:
    # Handle the specific exception
    handle_error()
except AnotherError as e:
    # Access the exception instance
    print(f"Error: {e}")
except (Error1, Error2):
    # Handle multiple exception types
    handle_multiple()
else:
    # Runs if no exception was raised
    success_path()
finally:
    # Always runs, regardless of exception
    cleanup()

Basic Exception Handling

Catch and handle specific exceptions:

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")
# Output: Cannot divide by zero!

Access the exception object for more details:

try:
    x = int("not a number")
except ValueError as e:
    print(f"Conversion failed: {e}")
# Output: Conversion failed: invalid literal for int()...

Catching Multiple Exceptions

Handle different exceptions in different ways:

try:
    data = {"key": "value"}
    value = data["missing"]
    num = int("abc")
except KeyError:
    print("Key not found!")
except ValueError:
    print("Invalid value!")
# Output: Key not found!

Catch multiple exceptions with a tuple:

try:
    x = int("abc")
except (ValueError, TypeError) as e:
    print(f"Error: {e}")
# Output: Error: invalid literal for int()...

The else Clause

The else block runs only when no exception occurs:

try:
    x = int("42")
except ValueError:
    print("Invalid number")
else:
    print(f"Successfully converted: {x}")
# Output: Successfully converted: 42

This is useful for code that should run only on success:

try:
    with open("config.txt") as f:
        config = f.read()
except FileNotFoundError:
    config = None
else:
    print("Config loaded successfully")
# Output: Config loaded successfully (if file exists)

The finally Clause

The finally block always executes, regardless of whether an exception occurred:

try:
    file = open("data.txt", "r")
    content = file.read()
except FileNotFoundError:
    content = None
finally:
    # This always runs
    print("Cleanup attempted")
# Output: Cleanup attempted

Use finally for cleanup that must happen:

try:
    conn = connect_to_database()
    result = conn.query("SELECT * FROM users")
except ConnectionError:
    result = None
finally:
    # Always close the connection
    if conn:
        conn.close()

Practical Examples

File handling with try/except/finally

def read_config(filename):
    file = None
    try:
        file = open(filename, "r")
        return file.read()
    except FileNotFoundError:
        return "{}"  # Default config
    finally:
        if file:
            file.close()

Better approach using context managers:

def read_config(filename):
    try:
        with open(filename, "r") as file:
            return file.read()
    except FileNotFoundError:
        return "{}"
# No need for finally—the with statement handles cleanup

Safe numeric conversion

def safe_int(value, default=0):
    try:
        return int(value)
    except (ValueError, TypeError):
        return default

print(safe_int("42"))      # Output: 42
print(safe_int("abc"))     # Output: 0
print(safe_int(None))       # Output: 0
print(safe_int("99", 10))  # Output: 99

Retry pattern with finally

import time

def fetch_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        conn = None
        try:
            conn = connect(url)
            return conn.fetch()
        except ConnectionError as e:
            print(f"Attempt {attempt + 1} failed: {e}")
            if attempt == max_retries - 1:
                raise
        finally:
            if conn:
                conn.close()
            time.sleep(1)  # Wait before retry

Suppressing vs. handling exceptions

Sometimes you want to ignore certain errors:

# Suppress KeyError only
data = {"name": "Alice", "age": 30}
value = data.get("missing")

# Or explicitly suppress
try:
    value = data["missing"]
except KeyError:
    pass  # Do nothing—just ignore the error

# Using dictionary get() is often clearer
value = data.get("missing", "default")

Exception Hierarchy

Python exceptions form a hierarchy. Catching a parent exception also catches its children:

try:
    x = int("abc")
except Exception:  # Catches all exceptions including ValueError
    print("Something went wrong")

# More specific—catch only what you can handle
try:
    risky_operation()
except ValueError:
    # Handle value errors
    pass
except Exception as e:
    # Let other exceptions propagate
    raise

Common exception types

  • ZeroDivisionError — Dividing by zero
  • ValueError — Wrong value type
  • TypeError — Wrong operation on type
  • KeyError — Missing dictionary key
  • FileNotFoundError — File does not exist
  • IndexError — List index out of range
  • AttributeError — Missing attribute
  • PermissionError — No permission

Raising Exceptions

Use raise to trigger exceptions (covered in detail in the raise keyword reference):

def validate_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative")
    return age

See Also