-1

In Python 3.6, returning from a finally block squashes all unhandled exceptions - Why?

Example:

def foo():
    print("Inside foo")
    raise ValueError("No good values supplied")
    print("Unreachable in foo")


def bar():
    print("Inside bar")
    try:
        foo()
        print("Unreachable in bar")
    finally:
        print("Finally block")
        return "A value"


print("Starting process")
res = bar()
print(f"Should be unreachable, because error is not handled - {res}")

If the finally block doesn't return, the exception is correctly propagated up the stack

This question is different to Weird Try-Except-Else-Finally behavior with Return statements, which is asking about the order of resolution of except blocks, because it is a construct that explicitly does not handle exceptions raised in the try part of the code. A naieve reading of the code, with an understanding of Python tenets, such as "explicit is better than implicit" would lead a developer not seeing this type of construct before to conclude that when an exception is raised in the try block, the finally would run, but the return would have no effect as the exception is unhandled and therefore would raise. The reality is, though, the exception is instead implicitly handled and the function returns successfully to the calling code

Simon Pratt
  • 165
  • 1
  • 3
  • 10
  • 1
    Because the `finally` block is supposed to execute whether or not the `try` block raised an exception, so if you write `return` there it means you want your function to return even when the `try` block raises an exception. A function cannot both return and raise, so therefore it doesn't raise. – kaya3 Apr 23 '21 at 09:20
  • No, that doesn't sorry. It's asking a different question. Mine is explicitly about the concept of a `try:`, `finally:` construct raising / not raising based on where the `return` sits. The link to PEP601 in one of the answers to that question is useful though, thank you – Simon Pratt Apr 23 '21 at 09:35
  • 2
    How about this one: [Why doesn't `finally: return` propagate an unhandled exception?](https://stackoverflow.com/q/38094811/12299000) – kaya3 Apr 23 '21 at 09:39
  • Yes, that one does. It explains the behaviour, but fails to explain why the behaviour exists this way. As per my edit, a dev not seeing this type of construct before cannot intuit (or would most likely incorrectly intuit) the behaviour – Simon Pratt Apr 23 '21 at 09:47
  • So your question is about the intentions of the Python language designers, if I understand correctly? – kaya3 Apr 23 '21 at 09:48
  • This is why PEP601 was suggested, and although rejected, it did make its way to [PEP8](https://www.python.org/dev/peps/pep-0008/#id51): *"Use of the flow control statements return/break/continue within the finally suite of a try...finally, where the flow control statement would jump outside the finally suite, is discouraged. __This is because such statements will implicitly cancel any active exception__ that is propagating through the finally suite"* – Tomerikoo Apr 23 '21 at 09:50
  • Yes, I guess thats right :) I'll keep that in mind in the future and be sure to not ask "why" questions again – Simon Pratt Apr 23 '21 at 09:57
  • I don't think there is anything specifically wrong with a "why is it designed this way?" question, but be careful to specify that's what you're asking about, and it's also worth clarifying whether you want to know about published statements/discussions by the language designers, or whether you just want to know in general what the reasons for designing it that way *might* be. The latter is harder to answer objectively since it veers towards opinion, but a good question along those lines can be asked. See [this discussion on meta.SO](https://meta.stackoverflow.com/q/260711/12299000) for more. – kaya3 Apr 23 '21 at 10:13

1 Answers1

1

The try collects every raised exception. If you want to know or react to the exception you would need to add an except: part. You can also specify on which exception you would like to react with except ValueError: and do specific error handling for this error. The finally part is always called at the end. It's meant to do a cleanup weather or not the try part runs successful.

chillking
  • 311
  • 1
  • 9