variable
variable

Reputation: 9714

Finally always runs just before the return in try block, then why update in finally block not affect value of variable returned by try block?

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

Upvotes: 23

Views: 3169

Answers (4)

adamkwm
adamkwm

Reputation: 1173

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)

Upvotes: 1

Youyoun
Youyoun

Reputation: 338

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.

Upvotes: 5

Adam.Er8
Adam.Er8

Reputation: 13413

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

Upvotes: 12

Mustafa Quraish
Mustafa Quraish

Reputation: 694

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.

Upvotes: 7

Related Questions