Why do we need the "finally" clause in Python?

PythonException HandlingTry Finally

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

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 a TypeError.
  • Other control flow statements such as continue and break statements.

Solution 2 - Python

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.

Solution 3 - Python

They are not equivalent. finally code is run no matter what else happens*. It is useful for cleanup code that has to run.


*: As Mark Byers commented, anything causes the process to terminate immediately also prevents the finally-code to run. The latter could be an os._exit(). or powercut, but an infinite loop or other things also fall into that category.

Solution 4 - Python

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.

Solution 5 - Python

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. The try > clause is executed, including any except and else clauses. If an > exception occurs in any of the clauses and is not handled, the > exception is temporarily saved. The finally clause is executed. If > there is a saved exception it is re-raised at the end of the finally > 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.

Solution 6 - Python

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.

Solution 7 - Python

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.

Solution 8 - Python

Here's a peice of code to clarify the difference:

...

try: 
  a/b
  print('In try block')
  
except TypeError:
  print('In except block')
  
finally: 
  print('In finally block')

print('Outside')

a, b = 0, 1

Output:

In try block 
In finally block 
Outside

(No errors, except block skipped.)


a, b = 1, 0

Output:

In finally block

Traceback (most recent call last):
a/b
ZeroDivisionError: division by zero

(No exception handling is specified for ZeroDivisionError and only the finally block is executed.)


a, b = 0, '1'

Output:

In except block 
In finally block 
Outside

(Exception is handled properly and the program is not interrupted.)


Note: If you have an except block to handle all types of errors, the finally block will be superfluous.

Solution 9 - Python

Using delphi professionally for some years taught me to safeguard my cleanup routines using finally. Delphi pretty much enforces the use of finally to clean up any resources created before the try block, lest you cause a memory leak. This is also how Java, Python and Ruby works.

resource = create_resource
try:
  use resource
finally:
  resource.cleanup

and resource will be cleaned up regardless of what you do between try and finally. Also, it won't be cleaned up if execution never reaches the try block. (i.e. create_resource itself throws an exception) It makes your code "exception safe".

As to why you actually need a finally block, not all languages do. In C++ where you have automatically called destructors which enforce cleanup when an exception unrolls the stack. I think this is a step up in the direction of cleaner code compared to try...finally languages.

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.

Solution 10 - Python

Finally can also be used when you want to run "optional" code before running the code for your main work and that optional code may fail for various reasons.

In the following example, we don't know precisely what kind of exceptions store_some_debug_info might throw.

We could run:

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 

But, most linters will complain about catching too vague of an exception. Also, since we're choosing to just pass for errors, the except block doesn't really add value.

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

The above code has the same effect as the 1st block of code but is more concise.

Solution 11 - Python

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.

Solution 12 - Python

Perfect example is as below:

try:
    #x = Hello + 20
    x = 10 + 20 
except:
    print 'I am in except block'
    x = 20 + 30
else:
    print 'I am in else block'
    x += 1
finally:
    print 'Finally x = %s' %(x)

Solution 13 - Python

A try block has just one mandatory clause: The try statement. The except, else and finally clauses are optional and based on user preference.

finally: Before Python leaves the try statement, it will run the code in the finally block under any conditions, even if it's ending the program. E.g., if Python ran into an error while running code in the except or else block, the finally block will still be executed before stopping the program.

Solution 14 - Python

Try running this code first without a finally block,

1 / 0 causes a divide by zero error.

    try:
        1 / 0    
        print(1)
        
    except Exception as e:
        1 / 0
        print(e)
        

Then try running this code,

    try:
        1 / 0    
        print(1)
        
    except Exception as e:
        1 / 0
        print(e)
   
    finally:
        print('finally')

For the first case you don't have a finally block,
So when an error occurs in the except block the program execution halts and you cannot execute anything after the except block.

But for the second case,
The error occurs but before the program halts python executes the finally block first and then causes the program to halt.
Thats is why you use finally and do stuff that is really important.

Solution 15 - Python

Run these Python3 codes to watch the need of finally:

CASE1:

count = 0
while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")
        finally:
            print("Your Attempts: {}".format(count))

CASE2:

count = 0

while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")

        print("Your Attempts: {}".format(count))

Try the following inputs each time:

  1. random integers
  2. correct code which is 586(Try this and you will get your answer)
  3. random strings

** At a very early stage of learning Python.

Solution 16 - Python

I was trying to run a code where i wanted to read excel sheets. Issue was, if there is a file which has no sheet named say : SheetSum I am not able to move it to error location!! Code i wrote was:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets['df_1'] = pd.read_excel(open(data_file,'rb'), 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

Giving Error :

> [WinError 32] The process cannot access the file because it is being > used by another process

I had to add full try except with finally block and tell finally i need to close the file in any case like:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    sheets_file = None
    try:
        print("Reading file: "+data_file)
        sheets_file = open(data_file,'rb')
        sheets['df_1'] = pd.read_excel(sheets_file, 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    finally:
        if sheets_file:
            sheets_file.close()
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

Otherwise, file still remains open is the background.

> If finally is present, it specifies a cleanup handler. The try > clause is executed, including any except and else clauses. If an > exception occurs in any of the clauses and is not handled, the > exception is temporarily saved. The finally clause is executed. If > there is a saved exception it is re-raised at the end of the finally > clause. If the finally clause raises another exception, the saved > exception is set as the context of the new exception.

..More Here

Solution 17 - Python

Just to enable Abhijit Sahu's comment on this answer to be seen much better and with syntax highlighting:

Like this, you can observe what happens with which code block when:

try: 
    x = Hello + 20 
    x = 10 + 20 
except: 
    print 'I am in except block' 
    x = 20 + 30 
else: 
    print 'I am in else block' 
    x += 1 
finally: 
    print 'Finally x = %s' %(x) 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRNAView Question on Stackoverflow
Solution 1 - PythonMark ByersView Answer on Stackoverflow
Solution 2 - PythonkindallView Answer on Stackoverflow
Solution 3 - PythonAntimonyView Answer on Stackoverflow
Solution 4 - PythoncaptainblackView Answer on Stackoverflow
Solution 5 - PythonEugene YarmashView Answer on Stackoverflow
Solution 6 - PythonSven MarnachView Answer on Stackoverflow
Solution 7 - PythonmhawkeView Answer on Stackoverflow
Solution 8 - PythonShubView Answer on Stackoverflow
Solution 9 - PythonnurettinView Answer on Stackoverflow
Solution 10 - PythonBrad JohnsonView Answer on Stackoverflow
Solution 11 - PythonkakhkAtionView Answer on Stackoverflow
Solution 12 - PythonAbhijit SahuView Answer on Stackoverflow
Solution 13 - PythonLawrence KrukruboView Answer on Stackoverflow
Solution 14 - PythonAkshay KadavView Answer on Stackoverflow
Solution 15 - PythonAshPythonView Answer on Stackoverflow
Solution 16 - Pythons_mjView Answer on Stackoverflow
Solution 17 - Pythoni_want_more_editsView Answer on Stackoverflow