-1

I was looking at this list of python quirks and was amused that this returns False:

def t():
    try:
        return True
    finally:
        return False

After seeing this I saw the answers here and here which presented the reason why, and that's that the finally clause will always be executed, no exceptions.

My question is, where is the previous return value stored:

def t():
    try:
        return True
    finally:
        ...

Why doesn't this return None but instead returns the original True?

And is it possible to access the going to be returned value programatically?

def t():
    try:
        return True
    finally:
        ...
        # if returning != None: return False

I'd like to know if it's possible to do this without using a variable for example:

def t():
    retval = None
    try:
        retval = "Set"
    finally:
        if retval != None:
            return retval
        else:
            return "Not Set"

and

def t():
    retval = None
    try:
        ...
    finally:
        if retval != None:
            return retval
        else:
            return "Not Set"

return 'Set' and 'Not Set' respectively.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
  • 1
    Obviously it's stored _somewhere_ so it can be used after the `finally:` clause (assuming that doesn't contain a `return` statement), but that's an implementation detail. – martineau Aug 07 '17 at 16:04

1 Answers1

3

Why doesn't this return None but instead returns the original True?

From the docs:

The finally clause is also executed “on the way out” when any other clause of the try statement is left via a break, continue or return statement.

So this means that if a return statement is present in the finally clause that value will be returned (since the finally block is guaranteed to execute fully, any return statement inside it will be executed as well). Otherwise, if the try/except block was going to return a value, that value is returned.

This means that

def t():
    try:
        print("Inside try")
        return "Return from try"
    finally:
        print("Inside finally")
        return "Return from finally"

Will execute exactly as:

def t():
    try:
        print("Inside try")
        # start of old finally block, executed "on the way out"
        print("Inside finally")
        return "Return from finally"
        # end of old finally block, inserted right before return statement in try
        return "Return from try"
    finally:
        pass

And is it possible to access the going to be returned value programatically?

No, you can't access the value after the return statement in other parts of the code without saving it.

EsotericVoid
  • 2,306
  • 2
  • 16
  • 25
  • *"No, you can't access the value after the return statement in other parts of the code without saving it."* Have you got an evidence to back this up, and I'm aware that the `finally` clause is also executed, but that quote doesn't explain why the `try/except` value is returned instead if the `finally` does not return, I'm aware that it does it, the question is why. In terms of answering *why* a walkthrough of python bytecode would be useful. – Nick is tired Aug 07 '17 at 16:08
  • 1
    Because as @martineau said, that is an implementation detail. For the other question, imagine that all the code inside the `finally` block is put *exactly before* any statement that returns a value / raises an exception (if present). If `finally` returns nothing or doesn't raise an exception, the program keeps going. I think this is explained well in the [docs](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement) (which are linked in one of the SO posts that you provided). – EsotericVoid Aug 07 '17 at 16:22