The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Catch one exception | except ValueError: number = 0 | View examples |
| Inspect an exception | except ValueError as error: print(error) | View examples |
| Catch related failures | except (TypeError, ValueError) as error: print(error) | View examples |
| Use ordered handlers | except FileNotFoundError: use_default() | View examples |
| Run after success | else: print(value) | View examples |
| Always clean up | finally: resource.close() | View examples |
| Raise an exception | raise ValueError("quantity must be positive") | View examples |
| Re-raise the current error | except OSError: log_failure(); raise | View examples |
| Chain a domain error | raise ConfigError("invalid port") from error | View examples |
| Hide incidental context | raise ValueError("unknown user") from None | View examples |
| Define a custom exception | class ConfigError(Exception): pass | View examples |
| Store error context | error = ValidationError(field="email", message="invalid address") | View examples |
| Convert at a boundary | value = int(text) | View examples |
| Use managed cleanup | with open("settings.txt", encoding="utf-8") as file: data = file.read() | View examples |
| Assert an invariant | assert total >= 0, "total cannot be negative" | View examples |
Catch exceptions only where the program can add context, recover, or translate them into a clearer domain error. Keep try blocks narrow, handle specific exception classes, let unexpected failures propagate, and use context managers for resources that need reliable cleanup.
Step by step
Detailed examples
Catch only expected exception types
An except clause also matches subclasses, so order specific handlers before broad base classes. Keep the try suite limited to operations expected to raise those errors; a broad try can accidentally convert an unrelated programming defect into a misleading fallback.
def parse_number(text):
try:
return int(text)
except (TypeError, ValueError) as error:
print(f"invalid number: {error}")
return 0
print(parse_number("12"))
print(parse_number("twelve")) 12
invalid number: invalid literal for int() with base 10: 'twelve'
0def use_default():
print("using defaults")
try:
open("missing-settings.txt", encoding="utf-8")
except FileNotFoundError:
use_default()
except OSError as error:
print(f"other file error: {error}") using defaultsSeparate success work from unconditional cleanup
else runs only when try succeeds and keeps later operations from being caught accidentally. finally runs on every exit path and is appropriate for cleanup, but a with statement is usually clearer for resources implementing the context-manager protocol. Avoid return in finally because it can suppress exceptions and earlier return values.
def parse(text):
try:
value = int(text)
except ValueError:
value = 0
else:
print(f"parsed {value}")
finally:
print("finished")
return value
print(parse("8"))
print(parse("bad")) parsed 8
finished
8
finished
0Raise, re-raise, and chain errors intentionally
Raise an exception when the current operation cannot satisfy its contract. A bare raise inside a handler preserves the current traceback. Raise from another exception when translating implementation details into a domain error; use from None only when the original context would confuse rather than help diagnosis.
def require_positive(quantity):
if quantity <= 0:
raise ValueError("quantity must be positive")
return quantity
try:
require_positive(0)
except ValueError as error:
print(error) quantity must be positiveclass ConfigError(Exception):
pass
def parse_port(text):
try:
return int(text)
except ValueError as error:
raise ConfigError("invalid port") from error
try:
parse_port("http")
except ConfigError as error:
print(error)
print(type(error.__cause__).__name__) invalid port
ValueErrortry:
raise OSError("disk unavailable")
except OSError as error:
print(f"logged: {error}")
try:
raise
except OSError:
print("propagated") logged: disk unavailable
propagatedModel domain failures with custom exceptions
Custom exception types let callers distinguish application failures without parsing message text. Derive normal recoverable errors from Exception, use names ending in Error, and keep structured attributes small and meaningful.
class ValidationError(Exception):
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"{field}: {message}")
error = ValidationError(field="email", message="invalid address")
print(error)
print(error.field) email: invalid address
emailHandle failures at useful boundaries
Low-level helpers should often allow built-in exceptions to propagate so a command, request handler, or job boundary can decide whether to retry, report, or abort. Context managers express cleanup without a wide catch and preserve the original exception if reading fails.
def parse_count(text):
return int(text)
try:
value = parse_count("many")
except ValueError:
value = 0
print(value) 0from pathlib import Path
Path("settings.txt").write_text("theme=dark", encoding="utf-8")
with open("settings.txt", encoding="utf-8") as file:
data = file.read()
print(data) theme=darkReserve assertions for internal invariants
assert documents a condition that should be impossible to violate when the program is correct. Python can remove assertions when optimization is enabled, so never use them for user input validation, permissions, or other required runtime checks.
subtotal = 12
discount = 2
total = subtotal - discount
assert total >= 0, "total cannot be negative"
print(total) 10Local code tester
Try Python exception handling
Edit and run the parser locally to practice specific handlers, custom errors, chaining, and cleanup.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



