Success-only and always: else and finally
`else` holds code that should run only when the `try` succeeded. `finally` holds code that must run no matter what, even when an error is on its way out.
- Trace the order in which
try,except,elseandfinallyblocks run - Move success-only work into
else, sotrycovers only the risky line - Use
finallyfor bookkeeping that must happen on every path, including an unhandled error
A try statement can have two more blocks. `else` runs only if the try block finished without an error: put the code that depends on success there, so it isn't accidentally protected by the except. `finally` runs last, on every path: success, a handled error, or an error that nobody catches. It exists for clean-up and bookkeeping that must not be skipped.
Run each example to see what it prints. Running examples doesn't count toward progress.
def attempt(text): try: amount = float(text) except ValueError: print(" except: not a number") else: print(" else: charged", amount) finally: print(" finally: attempt logged") print("A") attempt("19.99") print("B") attempt("free")
finally even runs when the error isn't handled at all. Its block runs first, then the error carries on and stops the program as before.
status = {"running": True}
try:
print(int(None))
except ValueError:
print("bad text")
finally:
status["running"] = False
print("status:", status)In real code finally releases whatever the work was holding: a "busy" flag, a counter of attempts, and in the Files & Directories module an open file. Here a payment processor counts every attempt, even ones that crash, so the dashboard's attempt total is never short.
def charge(stats, text): stats["attempts"] += 1 try: amount = float(text) except ValueError: stats["rejected"] += 1 return None else: stats["charged"] += amount return amount finally: print(f"after {text!r}: {stats}") stats = {"attempts": 0, "rejected": 0, "charged": 0} charge(stats, "12.93") charge(stats, "twelve")
When to use it: else when work should happen only after the risky step succeeded; finally for anything that must happen whatever the outcome. Mistakes to avoid: putting success-only work inside try, where an unrelated error in it would be caught by the wrong handler; and returning a value from finally, which silently replaces the function's real result and swallows errors.
tryfor the risky line,exceptfor the failure,elsefor success-only work,finallyfor always.finallyruns even when the error isn't handled, and even after areturn.- Keep success-only work out of
try, or the wrong handler may catch its bugs. - Next: raising your own errors, with messages that say exactly what was wrong.