Python confusion with return value in try-except-finally

441 Views Asked by At

Here is a piece of my code:

def main():
    num = 0
    try:
        raise Exception('This is the error message.')
    except Exception:
        num += 1
        return num
    finally:
        num += 1

a = main()
print(a)

The returning value is 1 instead of 2, this does not make a lot of sense for me.

I thought it would return 2 since finally should execute before returning the value.

Can someone help me to understand this?

4

There are 4 best solutions below

2
Patrick Haugh On BEST ANSWER

You're running into the difference between an identifier and a value. num += 1 is creating a new int object and assigning the num identifier to point to it. It does not change the int object the identifier is already pointing to. (For small values the int objects are cached but that's an implementation detail)

You can see the difference with an operation that does mutate the object in the below code:

def y():
    l = []
    try:
        raise Exception
    except Exception:
        print("except")
        l.append(1)
        return l
    finally:
        print("finally")
        l.append(2)

print(y())
# except
# finally
# [1, 2]
0
user2357112 On

The finally block does execute before returning the value, but the return value has already been computed.

return num evaluates num, getting 1, then the finally block starts. The finally block increments num, but the return value has already been evaluated, so it doesn't matter. At the end, the 1 computed earlier is returned.

0
Jair Júnior On

It's because you are returning in except block Using return word will end code execution in this function. To avoid it you could write like this:

def main():
 num = 0
 try:
    raise Exception('This is the error message.')
 except Exception:
    num += 1
 finally:
    num += 1
 return num

a = main()
print(a)
0
mozway On

The finally is executed (this is clearly defined in the documentation), but as you return an immutable object, the modification is unseen as your returned name is now part of a different scope.

This would work as you expect with a mutable object, for instance a list:

def main():
    lst = [0]
    try:
        raise Exception('This is the error message.')
    except Exception:
        lst[0] += 1
        return lst
    finally:
        lst[0] += 1
a = main()
print(a)

Output: [2]