23

Finally block runs just before the return statement in the try block, as shown in the below example - returns False instead of True:

>>> def bool_return():
...  try:
...    return True
...  finally:
...    return False
...
>>> bool_return()
False

Similarly, the following code returns value set in the Finally block:

>>> def num_return():
...  try:
...    x=100
...    return x
...  finally:
...    x=90
...    return x
...
>>> num_return()
90

However, for variable assignment without return statement in the finally block, why does value of variable updated by the finally block not get returned by the try block? Is the variable from finally block scoped locally in the finally block? Or is the return value from the try block held in memory buffer and unaffected by assignment in finally block? In the below example, why is the output 100 instead of 90?

>>> def num_return():
...  try:
...    x=100
...    return x
...  finally:
...    x=90
...
>>> num_return()
100

Similarly the following example:

In [1]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [2]: num_return()
Out[2]: [90]

In [3]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x[0]
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [4]: num_return()
Out[4]: 100
variable
  • 8,262
  • 9
  • 95
  • 215
  • 1
    Finally block always executes Refer: https://stackoverflow.com/questions/19805654/python-try-finally-block-returns#:~:text=A%20finally%20clause%20is%20always,finally%20clause%20has%20been%20executed. – pjk Jul 01 '20 at 14:15
  • 3
    `finally` clause executes *after* the `return` - at no previous point would it know it was supposed to execute. Put `return print("returning")` in the `try` block, and you will see the output from that `print`. It simply replaces the original return value if it happens to do a `return` of its own. – jasonharper Jul 01 '20 at 15:17

5 Answers5

11

A little experiment to help confirm what others have answered, is to replace x with a single-value list, like this:

def num_return():
  try:
    x=[100]
    return x
  finally:
    x[0] = 90

now the value returned is [90], so the list is indeed modified in the finally block.

BUT if you return x[0], you get 100 (even though we just based the fact that the list itself does change in the finally block).


In [1]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [2]: num_return()
Out[2]: [90]

In [3]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x[0]
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [4]: num_return()
Out[4]: 100
Adam.Er8
  • 12,675
  • 3
  • 26
  • 38
  • Please could you tell me what exactly this concept is called? – variable May 31 '21 at 18:30
  • @variable I'd say it is related to Python's Data Model, and namely: variables are references, ints are immutable, but lists are mutable. https://docs.python.org/3/reference/datamodel.html – Adam.Er8 Jun 02 '21 at 06:21
8

When you say return x, Python saves the value of the variable x at that point as the return value. Updating x later doesn't affect this.

Mustafa Quraish
  • 692
  • 4
  • 10
5

The following clause was taken from: https://docs.python.org/3/tutorial/errors.html (section 8.6)

If the try statement reaches a break, continue or return statement, the finally clause will execute just prior to the break, continue or return statement’s execution.

On your first example, return False is executed after return True, hence the result. This also explains the second example.

For the last one, your return x saves the value of x at that point of your code, changing the value of the variable x does not change the value of the return statement.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Youyoun
  • 338
  • 1
  • 5
  • It seems that this doc is not true and misleading. As ```return_stmt ::= "return" [expression_list]```, *expression_list* is evaluated before *finally* block execution. It should not be `the finally clause will execute just prior to the break, continue or return statement’s execution.`, but rather `the finally clause will execute just =>in the middle<= of the break, continue or return statement’s execution.` – ToSimplicity Jul 05 '20 at 02:25
1

I think the problem you have is more related to value assignment than what try and finally do. I suggest to read Facts and myths about Python names and values.

When you return a value, it just like assigning the value to a variable, result for example, and finally always execute to reassign the value. Then, your example code may be represent as:

# try 
result = True # return
# finally 
result = False # return (reassign value)
print(result) # Output: False

# try
x = 100 
result = x # return
# finally
x = 90 
result = x # return (reassign value)
print(result) # Output: 90

# try
x = 100
result = x # return
# finally
x = 90 # no return so result not updated
print(result) # Output: 100
print(x) # Output: 90 (x is changed actually)

# try
x = [100]
result = x # return the list (result refer to a list and list is mutable)
# finally
x[0] = 90 # changing the list in-place so it affects the result
print(result) # Output: [90]

# try
x = [100]
result = x[0] # return the integer (result refer to the integer)
# finally
# changing the list in-place which have no effect to result unless reassign value by return x[0]
x[0] = 90
print(result) # Output: 100
print(x) # Output: [90] (x is changed actually)
adamkwm
  • 1,155
  • 2
  • 6
  • 18
-1

So try is "Try this code" finally is "If everything goes properly then finally do this"