else and finally
Two more blocks complete the shape. else is for the lines that only make sense if the try succeeded. finally is for the lines that must run whatever happens — success, failure, or an exception nobody caught.
1else: only if nothing went wrong
Anything you write after the whole try statement runs whether it succeeded or not. else is the block that runs only on the clean path:
try:
result = 10 / 2
except ZeroDivisionError:
print('Cannot divide by zero.')
else:
print('No exception. Result:', result)No exception. Result: 5.0
You could have put that print inside the try and it would behave the same. The reason to use else is the rule from two lessons ago: keep the try block to the lines that can actually fail. The division can fail; printing the result cannot. Moving it to else says exactly that.
2finally: whatever happens
try:
result = 10 / 0
print('Result:', result)
except ZeroDivisionError:
print('Cannot divide by zero.')
finally:
print('This line runs either way.')Cannot divide by zero. This line runs either way.
try:
result = 10 / 2
print('Result:', result)
except ZeroDivisionError:
print('Cannot divide by zero.')
finally:
print('This line runs either way.')Result: 5.0 This line runs either way.
Same last line both times. That is the entire promise of finally, and it is a stronger promise than it looks — because it holds even when the exception is not caught:
print('start')
try:
marks = [80, 90]
print(marks[5])
finally:
print('finally ran anyway')
print('this is never reached')start
finally ran anyway
Traceback (most recent call last):
File "finally_uncaught.py", line 5, in <module>
print(marks[5])
~~~~~^^^
IndexError: list index out of range print(marks[5])Raises IndexError. There is no except block at all, so nothing is going to handle it — the program is on its way out.
finally:Runs anyway, on the way out. This is the whole point: finally is Python's promise that these lines happen even when everything else has failed.
print('this is never reached')Does NOT run. finally is not a rescue — the exception carries on afterwards and still ends the program.
finally is for cleaning up, not for recovering. It does not catch anything and it does not stop the program ending. It guarantees that whatever is inside it happens first — closing what you opened, releasing what you took, printing where you got to.3What people actually use it for
The pattern is always the same shape: something is opened, something risky happens to it, and it must be closed whether that risky part worked or not.
Open a file, read it, close it. If the reading fails, the file still has to be closed — and finally is where that goes. You will meet this properly in the File Handling chapter.
A program talking to a database opens a connection first. Leaving one open because something failed halfway is a real and expensive bug.
Even just a final message. If a long job fails at step 7 of 10, the log line saying so belongs in finally, so it is written either way.
4All four blocks together
try, then any number of except blocks, then else, then finally — in that order. You rarely need all four at once, but it is worth seeing the whole thing once:
reading = '88'
try:
marks = int(reading)
result = 100 / marks
except ValueError:
print('That was not a number.')
except ZeroDivisionError:
print('Marks cannot be zero here.')
else:
print('Result:', round(result, 2))
finally:
print('Attempt finished.')Result: 1.14 Attempt finished.
Change one word and a different path runs — but the last line does not move:
reading = 'eighty'
try:
marks = int(reading)
result = 100 / marks
except ValueError:
print('That was not a number.')
except ZeroDivisionError:
print('Marks cannot be zero here.')
else:
print('Result:', round(result, 2))
finally:
print('Attempt finished.')That was not a number. Attempt finished.
tryAlways starts. Stops the instant something goes wrong.
exceptOnly if a matching exception was raised.
elseOnly if the try finished with no exception at all.
finallyAlways. Caught, uncaught, or nothing wrong at all.
except blocks come before else, and finally is last. Writing them in another order is a SyntaxError — Python will not run the file at all.5Recap
It holds the lines that need the try to have succeeded — which keeps the try block down to the lines that can actually fail.
Exception caught, exception uncaught, or nothing wrong at all. It is the only block with that guarantee.
An uncaught exception still ends the program. finally just gets its turn first, on the way out.
Closing a file, releasing a connection, writing the last log line. Anything that must happen even after a failure.
try, then except blocks, then else, then finally. Any other order is a SyntaxError.
- 1
Run the full four-block program with
'88','eighty'and'0'.Hint · Three different middles, and
Attempt finished.at the end of all three. - 2
Write a
trywith afinallyand noexcept, and make it fail.Hint · The
finallyruns, then the traceback appears. Both. - 3
Move the success
printfrom thetryinto anelseand check nothing changes.Hint · Nothing should. The gain is in what the code now says about which lines can fail.
- 4
Put
finallybeforeexceptand read the error.Hint · A
SyntaxError— so not one line of the file runs.
A try block raises an exception and there is no except. What happens to finally?
When does the else block run?
What is the correct order of the blocks?