LambdaLabTM
Computer Science · Class 12 · Exception Handling
Exceptionsfinally⏱️ 14 min read

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:

with_else.py
try:
    result = 10 / 2
except ZeroDivisionError:
    print('Cannot divide by zero.')
else:
    print('No exception. Result:', result)
Output
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

with_finally.py
try:
    result = 10 / 0
    print('Result:', result)
except ZeroDivisionError:
    print('Cannot divide by zero.')
finally:
    print('This line runs either way.')
Output
Cannot divide by zero.
This line runs either way.
finally_no_error.py
try:
    result = 10 / 2
    print('Result:', result)
except ZeroDivisionError:
    print('Cannot divide by zero.')
finally:
    print('This line runs either way.')
Output
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:

finally_uncaught.py
print('start')

try:
    marks = [80, 90]
    print(marks[5])
finally:
    print('finally ran anyway')

print('this is never reached')
Output
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.

Key Takeaway
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.

Files

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.

Connections

A program talking to a database opens a connection first. Leaving one open because something failed halfway is a real and expensive bug.

Saying where you got to

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:

full_shape.py
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.')
Output
Result: 1.14
Attempt finished.

Change one word and a different path runs — but the last line does not move:

full_shape_bad.py
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.')
Output
That was not a number.
Attempt finished.
Which block runs when
try

Always starts. Stops the instant something goes wrong.

except

Only if a matching exception was raised.

else

Only if the try finished with no exception at all.

finally

Always. Caught, uncaught, or nothing wrong at all.

Watch Out
The order is fixed. 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.
all_four.py

5Recap

else runs on the clean path only

It holds the lines that need the try to have succeeded — which keeps the try block down to the lines that can actually fail.

finally runs whatever happens

Exception caught, exception uncaught, or nothing wrong at all. It is the only block with that guarantee.

finally does not rescue

An uncaught exception still ends the program. finally just gets its turn first, on the way out.

It is for cleaning up

Closing a file, releasing a connection, writing the last log line. Anything that must happen even after a failure.

The order is fixed

try, then except blocks, then else, then finally. Any other order is a SyntaxError.

✍️ Now write these yourself
  1. 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. 2

    Write a try with a finally and no except, and make it fail.

    Hint · The finally runs, then the traceback appears. Both.

  3. 3

    Move the success print from the try into an else and check nothing changes.

    Hint · Nothing should. The gain is in what the code now says about which lines can fail.

  4. 4

    Put finally before except and read the error.

    Hint · A SyntaxError — so not one line of the file runs.

Quick Check

A try block raises an exception and there is no except. What happens to finally?

Quick Check

When does the else block run?

Quick Check

What is the correct order of the blocks?