Question :
I am not sure why we need finally
in try...except...finally
statements. In my opinion, this code block
try:
run_code1()
except TypeError:
run_code2()
other_code()
is the same with this one using finally
:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
Am I missing something?
Answer #1:
It makes a difference if you return early:
try:
run_code1()
except TypeError:
run_code2()
return None # The finally block is run before the method returns
finally:
other_code()
Compare to this:
try:
run_code1()
except TypeError:
run_code2()
return None
other_code() # This doesn't get run if there's an exception.
Other situations that can cause differences:
- If an exception is thrown inside the except block.
- If an exception is thrown in
run_code1()
but it’s not aTypeError
. - Other control flow statements such as
continue
andbreak
statements.
Answer #2:
You can use finally
to make sure files or resources are closed or released regardless of whether an exception occurs, even if you don’t catch the exception. (Or if you don’t catch that specific exception.)
myfile = open("test.txt", "w")
try:
myfile.write("the Answer is: ")
myfile.write(42) # raises TypeError, which will be propagated to caller
finally:
myfile.close() # will be executed before TypeError is propagated
In this example you’d be better off using the with
statement, but this kind of structure can be used for other kinds of resources.
A few years later, I wrote a blog post about an abuse of finally
that readers may find amusing.
Answer #3:
They are not equivalent. Finally code is run no matter what else happens. It is useful for cleanup code that has to run.
Answer #4:
To add to the other answers above, the finally
clause executes no matter what whereas the else
clause executes only if an exception was not raised.
For example, writing to a file with no exceptions will output the following:
file = open('test.txt', 'w')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
OUTPUT:
Writing to file.
Write successful.
File closed.
If there is an exception, the code will output the following, (note that a deliberate error is caused by keeping the file read-only.
file = open('test.txt', 'r')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
OUTPUT:
Could not write to file.
File closed.
We can see that the finally
clause executes regardless of an exception. Hope this helps.
Answer #5:
The code blocks are not equivalent. The finally
clause will also be run if run_code1()
throws an exception other than TypeError
, or if run_code2()
throws an exception, while other_code()
in the first version wouldn’t be run in these cases.
Answer #6:
As explained in the documentation, the finally
clause is intended to define clean-up actions that must be executed under all circumstances.
If
finally
is present, it specifies a ‘cleanup’ handler. Thetry
clause is executed, including anyexcept
andelse
clauses. If an
exception occurs in any of the clauses and is not handled, the
exception is temporarily saved. Thefinally
clause is executed. If
there is a saved exception it is re-raised at the end of thefinally
clause.
An example:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
As you can see, the finally
clause is executed in any event. The TypeError
raised by dividing two strings is not handled by the except
clause and therefore re-raised after the finally
clause has been executed.
In real world applications, the finally clause is useful for releasing external resources (such as files or network connections), regardless of whether the use of the resource was successful.
Answer #7:
In your first example, what happens if run_code1()
raises an exception that is not TypeError
? … other_code()
will not be executed.
Compare that with the finally:
version: other_code()
is guaranteed to be executed regardless of any exception being raised.
Answer #8:
finally
is for defining “clean up actions”. The finally
clause is executed in any event before leaving the try
statement, whether an exception (even if you do not handle it) has occurred or not.
I second @Byers’s example.