Introduction
Exceptions are Python's mechanism for signaling and handling errors. Understanding the try/except/else/finally block, the exception hierarchy, and Python 3.14's bracketless except syntax gives you precise control over error handling in any application.
Key Concepts
try/except: Execute code and catch specific errors.else: Runs only when no exception was raised in thetryblock.finally: Runs unconditionally, for cleanup like closing files or connections.- Exception hierarchy: A tree of built-in exceptions rooted at
BaseException, withExceptionas the parent of most catchable errors. - Bracketless except (Python 3.14+): Catch multiple exception types without parentheses.
Real World Context
Every production application needs robust error handling. A web server catches ValueError on bad input, ConnectionError on database failures, and logs unexpected exceptions for debugging. The exception hierarchy matters because catching Exception also catches ValueError, KeyError, and everything under it -- which can mask bugs if you are not careful.
Deep Dive
Basic try/except
pythontry: result = 10 / 0 except ZeroDivisionError: print("Cannot divide by zero")
Multiple Exception Types
pythontry: value = int(input()) result = 10 / value except ValueError: print("Invalid input") except ZeroDivisionError: print("Cannot divide by zero") except (TypeError, AttributeError) as e: print(f"Type error: {e}")
Bracketless except (Python 3.14+)
Python 3.14 allows catching multiple exception types without parentheses:
python# Before 3.14 -- parentheses required try: connect() except (TimeoutError, ConnectionRefusedError): print("Network error") # Python 3.14+ -- no parentheses needed try: connect() except TimeoutError, ConnectionRefusedError: print("Network error")
This also works with except* for exception groups.
The Complete try Statement
pythontry: # Code that might raise an exception result = risky_operation() except SomeError as e: # Handle the exception log_error(e) except Exception as e: # Catch-all (use sparingly) print(f"Unexpected error: {e}") else: # Runs ONLY if no exception was raised process(result) finally: # ALWAYS runs (cleanup) cleanup()
Exception Hierarchy
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── StopIteration
├── ArithmeticError
│ ├── ZeroDivisionError
│ └── OverflowError
├── LookupError
│ ├── KeyError
│ └── IndexError
├── ValueError
└── ...
Common Pitfalls
- Catching
Exceptiontoo broadly -- A bareexcept Exception:swallows errors you did not expect, making bugs invisible. Catch the specific type you anticipate. - Using
except:without a type -- This catches evenKeyboardInterruptandSystemExit, making it impossible to stop the program with Ctrl+C. Always specify at leastException. - Putting too much code in
try-- Only wrap the specific line(s) that might raise. Extra code in thetryblock risks catching unrelated errors.
Best Practices
- Use
elsefor success-path logic -- Code inelseonly runs whentrysucceeds and will not accidentally catch new exceptions. - Use
finallyfor cleanup -- Closing files, releasing locks, and rolling back transactions belong infinally(or better yet, use a context manager).
Summary
try/exceptcatches exceptions;elsehandles the success path;finallyalways runs for cleanup.- The exception hierarchy determines which
exceptclause catches which errors. - Python 3.14 introduces bracketless
exceptfor catching multiple types. - Always catch specific exception types rather than broad
Exceptionor bareexcept. - Keep
tryblocks minimal to avoid masking unrelated errors.
Code Examples
python
# Catching the exception object
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as e:
print(f"Error at line {e.lineno}, column {e.colno}")
print(f"Message: {e.msg}")
# Bare except (avoid!)
try:
something()
except: # Catches EVERYTHING including KeyboardInterrupt
pass # Never do this in production