Web Analytics

Exceptions Basics

Intermediate ~25 min read

Errors happen - files go missing, users enter invalid data, networks fail. Python's exception system lets you handle these gracefully instead of crashing. Understanding the difference between syntax errors and runtime exceptions, knowing the common exception types, and being able to read tracebacks are essential skills for every Python developer!

Syntax Errors vs Exceptions

Syntax errors occur when Python can't parse your code - it doesn't understand what you wrote. These must be fixed before the program can run. Exceptions occur during execution when something goes wrong at runtime. The code is valid Python, but the operation failed (like dividing by zero).

Output
Click Run to execute your code
Key Difference:
SyntaxError - Python can't understand your code (missing colons, unmatched brackets)
- Detected before the program runs
- Cannot be caught with try/except

Exception - Code is valid but fails at runtime (divide by zero, file not found)
- Detected during execution
- Can be caught and handled

Common Exception Types

Python has dozens of built-in exception types, each for specific error conditions. Knowing the common ones helps you write better error handling and debug faster. The most frequent exceptions you'll encounter are TypeError, ValueError, KeyError, IndexError, and FileNotFoundError.

Output
Click Run to execute your code
Quick Exception Reference:
TypeError - Wrong type: "a" + 1, len(42)
ValueError - Bad value: int("abc")
IndexError - Bad index: list[999]
KeyError - Missing key: dict["missing"]
AttributeError - No attribute: "str".append()
FileNotFoundError - File missing: open("nope.txt")

Exception Hierarchy

Python exceptions form a class hierarchy. All exceptions inherit from BaseException, and most inherit from Exception. Understanding the hierarchy helps you catch related exceptions together - catching LookupError catches both IndexError and KeyError.

Output
Click Run to execute your code
Don't catch BaseException! Only catch Exception or more specific types. BaseException includes KeyboardInterrupt (Ctrl+C) and SystemExit - catching these prevents users from stopping your program!

Reading Tracebacks

When an exception occurs, Python prints a traceback - a record of where the error happened and how the code got there. Read tracebacks from bottom to top: the error type is at the bottom, and the call stack shows how you got there.

Output
Click Run to execute your code
Reading Tracebacks:
1. Start at the BOTTOM - that's the error type and message
2. Read UP to see the call stack
3. Look for YOUR code (not library files)
4. The last line of your code before the error is usually the problem
5. Check variable values at that point

Common Mistakes

1. Catching too broadly

# Wrong - catches everything, hides bugs!
try:
    result = do_something()
except:  # Bare except - NEVER do this!
    pass

# Also wrong - too broad
except Exception:
    pass  # Silently ignoring all errors

# Correct - catch specific exceptions
try:
    result = do_something()
except ValueError:
    print("Invalid value provided")
except FileNotFoundError:
    print("File not found")

2. Ignoring the error message

# Wrong - throwing away useful info!
try:
    data = json.loads(user_input)
except json.JSONDecodeError:
    print("Invalid JSON")  # What was wrong?

# Correct - use the error message
try:
    data = json.loads(user_input)
except json.JSONDecodeError as e:
    print(f"Invalid JSON at position {e.pos}: {e.msg}")

3. Catching exceptions in wrong order

# Wrong - specific exception never reached!
try:
    open("file.txt")
except OSError:
    print("OS error")  # Catches FileNotFoundError too!
except FileNotFoundError:
    print("File not found")  # Never runs!

# Correct - specific exceptions first
try:
    open("file.txt")
except FileNotFoundError:
    print("File not found")  # Runs for missing files
except OSError:
    print("Other OS error")  # Catches remaining OS errors

4. Using exceptions for flow control

# Wrong - using exceptions as if/else
try:
    value = my_dict[key]
except KeyError:
    value = default

# Correct - use dict.get() or 'in' check
value = my_dict.get(key, default)

# Or
if key in my_dict:
    value = my_dict[key]
else:
    value = default

5. Not reading the full traceback

# Error: AttributeError: 'NoneType' has no attribute 'strip'
# Many developers just see "AttributeError" and get confused

# The key info is 'NoneType' - something returned None!
# Check what could be None:

result = get_user_input()  # This returned None!
cleaned = result.strip()   # Can't call .strip() on None

# Fix: Check for None
result = get_user_input()
if result is not None:
    cleaned = result.strip()

Exercise: Exception Identifier

Task: Create a function that identifies what type of exception a piece of code raises.

Requirements:

  • Write a function that takes a callable and returns the exception name
  • Return "No exception" if no error occurs
  • Test with various error-causing operations
Output
Click Run to execute your code
Show Solution
def identify_exception(func):
    """Run a function and return the exception type name."""
    try:
        func()
        return "No exception"
    except Exception as e:
        return type(e).__name__


# Test cases
test_cases = [
    ("Division by zero", lambda: 1 / 0),
    ("String + int", lambda: "a" + 1),
    ("List index", lambda: [1, 2, 3][10]),
    ("Dict key", lambda: {}["missing"]),
    ("Int parse", lambda: int("hello")),
    ("File open", lambda: open("nonexistent.txt")),
    ("No error", lambda: 1 + 1),
]

print("=== Exception Identifier ===\n")
for name, func in test_cases:
    result = identify_exception(func)
    print(f"{name:20} -> {result}")

# Expected output:
# Division by zero     -> ZeroDivisionError
# String + int         -> TypeError
# List index           -> IndexError
# Dict key             -> KeyError
# Int parse            -> ValueError
# File open            -> FileNotFoundError
# No error             -> No exception

Summary

  • Syntax errors: Detected before running, can't be caught
  • Exceptions: Runtime errors, can be caught with try/except
  • TypeError: Wrong type for operation
  • ValueError: Right type, invalid value
  • KeyError: Dictionary key not found
  • IndexError: List index out of range
  • FileNotFoundError: File doesn't exist
  • Hierarchy: Exceptions inherit from parent classes
  • Tracebacks: Read bottom-to-top for error details
  • Best practice: Catch specific exceptions, not broad ones

What's Next?

Now that you understand what exceptions are, let's learn how to handle them with try/except. You'll learn to catch exceptions gracefully, handle multiple exception types, and keep your programs running even when errors occur!