Error handling: try / except / raise
Things go wrong — bad input, a missing file, a network timeout, division by zero. By default an exception crashes the program with a traceback. try/except lets you catch that and respond instead of dying.
Code that might fail goes in the try block; the except block runs only if a matching exception is raised. The golden rule: catch the narrowest exception you can. except ValueError: catches a conversion failure and nothing else; bare except: (or except Exception:) swallows *everything*, including typos and bugs you actually want to see.
Two optional clauses round it out:
else:— runs only if thetryblock did not raise (the success path).finally:— runs no matter what, error or not (cleanup: close a file, release a lock).
You can also throw your own with raise SomeError('message') — useful for signalling that input is invalid in a way callers can catch. For domain-specific failures, define a custom exception by subclassing Exception.
Syntax
try:
risky()
except ValueError as e: # catch a SPECIFIC type
handle(e)
except (KeyError, TypeError): # catch several
...
else:
# ran only if no exception
...
finally:
# always runs (cleanup)
...
raise ValueError('bad input') # throw one yourself
class ConfigError(Exception): # custom exception
passWorked examples
Catch a specific exception, return a fallback
def safe_int(value):
try:
return int(value)
except ValueError:
return None
print(safe_int('42')) # 42
print(safe_int('nope')) # NoneRaise your own, with a clear message
def safe_divide(a, b):
if b == 0:
raise ValueError('Cannot divide by zero')
return a / b
print(safe_divide(10, 2)) # 5.0
# safe_divide(5, 0) → ValueError: Cannot divide by zeroelse and finally
try:
x = int('5')
except ValueError:
print('bad input')
else:
print(f'parsed {x}') # runs (no error)
finally:
print('done') # always runs
# Output:
# parsed 5
# doneCommon mistakes & gotchas
Bare except hides real bugs
except: or except Exception: catches *everything* — including NameError from a typo or a KeyboardInterrupt. A bug then looks like normal behaviour and you debug for hours. Catch the specific exception you expect, and let the rest surface.
Swallowing an error silently
except ValueError: pass makes the failure vanish with no trace. If you catch an error, do something meaningful — return a fallback, log it, or re-raise. Silent pass is how data corruption goes unnoticed.
try blocks should be small
Wrapping ten lines in one try makes it unclear which line you expected to fail, and a different error gets caught by accident. Keep the try around just the risky operation; put the rest outside it.
Why it matters
The difference between a script and a robust program is what happens when things go wrong. Professional code anticipates failure — bad input, missing files, flaky networks — and handles it cleanly instead of dumping a traceback on the user. Narrow, deliberate `try`/`except` is the backbone of that resilience.