An exception handler intercepts an error so a program can respond rather than immediately exit. In Python, execution searches back up the call stack for a handler; if none is found, the application exits and displays a stack trace. section 5.1 section 5.2
Handle an exception where there is enough context to choose a useful response. A function with a narrow responsibility may let an exception propagate to a higher-level handler, which can retry the operation, correct data, or explain what the user can do. section 5.2.1 section 5.2.3
def func_a():
dividend = float(input("Enter a dividend value: "))
divisor = float(input("Enter a divisor value: "))
result = func_b(dividend, divisor)
print(f"dividing {dividend} by {divisor} = {result}")
def func_b(dividend: float, divisor: float) -> float:
return func_c(dividend, divisor)
def func_c(dividend: float, divisor: float) -> float:
return dividend / divisor
successful = False
while not successful:
try:
func_a()
except ZeroDivisionError as e:
print(f"The divisor can't be a zero value, error:", e)
except ValueError as e:
print(
f"The dividend and divisor must be a string that represents a
number, error:",
e,
)
else:
successful = True
finally:
if successful:
print("Thanks for running the program")
else:
print("Try entering a dividend and divisor again")
A division program lets ZeroDivisionError and ValueError propagate to a higher-level handler, which prompts the user to try again until the operation succeeds. section 5.2.4
A useful handler should:
- Catch exceptions the code can meaningfully handle, rather than catching broadly by default. section 5.2.1 section 5.2.4
- Give the user useful feedback or log the problem; silently discarding an exception hides information from both users and developers. section 5.2.3 section 5.2.4
- Use optional else for success and finally for code that should run whether an exception occurs or not. section 5.2 section 5.2.4
