Errors and exceptions
Raise clear errors and catch failures at useful boundaries
Raising and catching errors
An exception reports that an operation could not produce its normal result. A traceback identifies the exception and the calls leading to it. Read the final line for the immediate failure, then inspect the relevant frames.
Use a narrow try block and catch specific exception types. Other errors propagate to the caller. Parsing and domain validation can fail separately:
def read_percentage(text):
number = int(text)
if not 0 <= number <= 100:
raise ValueError("percentage must be between 0 and 100")
return number
try:
read_percentage("120")
except ValueError as error:
print(error) # percentage must be between 0 and 100Here conversion succeeds, but the range is invalid. An input such as "many" fails during conversion. Both are ValueError because the supplied value is unacceptable.
Cleanup and propagation
elseruns when thetrybody completes normally.finallyruns during ordinary exits, including exceptions and returns. Use it for cleanup.- Bare
raisere-raises the active exception. raise ... from errorpreserves the cause when translating between error categories.
A custom exception gives callers a stable category across lower-level failures:
class InvalidConfiguration(Exception):
pass
def read_port(settings):
try:
return int(settings["port"])
except (KeyError, ValueError) as error:
raise InvalidConfiguration("port is missing or invalid") from error
try:
read_port({"port": "many"})
except InvalidConfiguration as error:
print(type(error.__cause__).__name__) # ValueError__cause__ preserves the conversion error. A wrong runtime type such as a list still raises TypeError; the handler deliberately translates only KeyError and ValueError. This example checks representation, not the valid port range.
Gotchas
- Catch where recovery is possible: reject a row, ask for another value, or stop. A broad catch that returns zero can turn a defect into plausible data.
- Bare
except:also catches termination requests such asKeyboardInterrupt. Routine recovery should catch specificExceptionsubclasses. returninfinallycan replace a result or suppress a pending exception. Cleanup failures can also replace the visible error.- If a batch continues after rejection, retain the failure details and define whether earlier side effects remain committed.
Use custom categories when callers need them. Test error types and state after failure; require exact messages only when they are part of the interface.
Put it into practice
Implement the exercise in a full-screen workspace, then run its tests.