Exceptions
14 min
When something goes wrong, Python raises an exception — normally that
crashes your program with a traceback. try/except lets you catch it
and decide what to do instead of crashing.
try:
result = 10 / 0
except ZeroDivisionError:
result = None
print("can't divide by zero")
Only wrap the specific line(s) that might fail — putting an entire large
function inside one try block makes it hard to tell which line actually
raised, when something goes wrong later.
Catching a specific exception type (IndexError) means a genuinely different bug elsewhere in the function won't get silently swallowed by an overly broad except.
Always catch the narrowest exception type that matches what you expect to
go wrong — ValueError for a bad conversion, KeyError for a missing
dict key, ZeroDivisionError for division, IndexError for an
out-of-range index. A bare except: (or except Exception:, which is
only slightly narrower) catches everything, including bugs you didn't
anticipate — that turns a loud crash (which tells you something's wrong)
into a silent wrong answer, which is much harder to debug later.
def to_int(s):
try:
return int(s)
except ValueError:
return None
Write a function `safe_divide(a, b)` that returns `a / b`, or the string 'undefined' if `b` is 0 — catch the specific exception `/` raises, don't check `b == 0` beforehand.
Write a function `parse_int_list(strings)` that converts each string in `strings` to an int, skipping any that fail to convert, and returns the successfully-converted ints in order.
What's the risk of a bare `except:` (with no exception type) compared to `except Exception:`?
You can catch specific exception types with try/except and know why overly broad exception handling is a real bug risk, not just a style preference.