Re: Try-except-finally paradox
Terry Reedy tjre...@udel.edu writes: I do not have any information on the topic, but I *imagine* that the when RETURN_VALUE opcode is evaluated within the context of an except block, it triggers a check for whether a corresponding finally block exists and should it exist, it is triggered, much like a callback. So, my *imaginary* algorithm works like this: return: if within an except block EB: if EB has a correspoinding final block FB run FB else do return else do return In Jessica's example, as the finally block executes a RETURN_VALUE opcode, and as this is *probably* a jump to the caller, the rest of the code does not get a chance to be executed. As I have said earlier, I by no means assert the truth of this idea I've explained here, but it seems quite reasonable to me. gk On 1/30/2014 7:05 AM, Dave Angel wrote: Jessica Ross deathwea...@gmail.com Wrote in message: I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? The finally has to happen before any return inside the try or the except. And once you're in the finally clause you'll finish it before resuming the except clause. Since it has a return, that will happen before the other returns. The one in the except block will never get reached. It's the only reasonable behavior., to my mind. Checking with the disassembled code, it appears that the except return happens first and is then caught and the value over-written 2 0 SETUP_FINALLY 45 (to 48) 3 SETUP_EXCEPT16 (to 22) 3 6 LOAD_GLOBAL 0 (Exception) 9 LOAD_CONST 1 ('Exception raised during try') 12 CALL_FUNCTION1 (1 positional, 0 keyword pair) 15 RAISE_VARARGS1 18 POP_BLOCK 19 JUMP_FORWARD22 (to 44) 422 POP_TOP 23 POP_TOP 24 POP_TOP 5 25 LOAD_GLOBAL 1 (print) 28 LOAD_CONST 2 ('Except after try') 31 CALL_FUNCTION1 (1 positional, 0 keyword pair) 34 POP_TOP 6 35 LOAD_CONST 3 (True) 38 RETURN_VALUE 39 POP_EXCEPT 40 JUMP_FORWARD 1 (to 44) 43 END_FINALLY 44 POP_BLOCK 45 LOAD_CONST 0 (None) 848 LOAD_GLOBAL 1 (print) 51 LOAD_CONST 4 ('Finally') 54 CALL_FUNCTION1 (1 positional, 0 keyword pair) 57 POP_TOP 9 58 LOAD_CONST 5 (False) 61 RETURN_VALUE 62 END_FINALLY 10 63 LOAD_CONST 0 (None) 66 RETURN_VALUE -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On Thu, Jan 30, 2014 at 11:05 PM, Dave Angel da...@davea.name wrote: The finally has to happen before any return inside the try or the except. And once you're in the finally clause you'll finish it before resuming the except clause. Since it has a return, that will happen before the other returns. The one in the except block will never get reached. It's the only reasonable behavior., to my mind. It's arguable that putting a return inside a finally is unreasonable behaviour, but that's up to the programmer. A finally clause can be used to do what might be done in C++ with a destructor: no matter how this function/block exits, do this as you unwind the stack. In C++, I might open a file like this: void func() { ofstream output(output.txt); // do a whole lot of stuff ... // at the close brace, output.~output() will be called, which will close the file } In Python, the equivalent would be: def func(): try: output = open(output.txt, w) # do a whole lot of stuff ... finally: output.close() (Actually, the Python equivalent would be to use a 'with' clause for brevity, but 'with' uses try/finally under the covers, so it comes to the same thing.) The concept of the finally clause is: Whether execution runs off the end, hits a return statement, or throws an exception, I need you do this before anything else happens. Having a return statement inside 'finally' as well as in 'try' is a bit of a corner case, since you're now saying Before you finish this function and return something, I need you to return something else, which doesn't usually make sense. If you think Python's behaviour is confusing, first figure out what you would expect to happen in this situation :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On 2014-01-30 13:02, Chris Angelico wrote: On Thu, Jan 30, 2014 at 11:05 PM, Dave Angel da...@davea.name wrote: The finally has to happen before any return inside the try or the except. And once you're in the finally clause you'll finish it before resuming the except clause. Since it has a return, that will happen before the other returns. The one in the except block will never get reached. It's the only reasonable behavior., to my mind. It's arguable that putting a return inside a finally is unreasonable behaviour, but that's up to the programmer. A finally clause can be used to do what might be done in C++ with a destructor: no matter how this function/block exits, do this as you unwind the stack. In C++, I might open a file like this: void func() { ofstream output(output.txt); // do a whole lot of stuff ... // at the close brace, output.~output() will be called, which will close the file } In Python, the equivalent would be: def func(): try: output = open(output.txt, w) # do a whole lot of stuff ... finally: output.close() (Actually, the Python equivalent would be to use a 'with' clause for brevity, but 'with' uses try/finally under the covers, so it comes to the same thing.) The concept of the finally clause is: Whether execution runs off the end, hits a return statement, or throws an exception, I need you do this before anything else happens. Having a return statement inside 'finally' as well as in 'try' is a bit of a corner case, since you're now saying Before you finish this function and return something, I need you to return something else, which doesn't usually make sense. If you think Python's behaviour is confusing, first figure out what you would expect to happen in this situation :) One of the reasons that the 'with' statement was added was to prevent the mistake that you've just done. ;-) What if the file can't be opened? -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On Fri, Jan 31, 2014 at 12:11 AM, MRAB pyt...@mrabarnett.plus.com wrote: One of the reasons that the 'with' statement was added was to prevent the mistake that you've just done. ;-) What if the file can't be opened? Yeah, whoops. The open shouldn't be inside try/finally. def func(): output = open(output.txt, w) try: # do a whole lot of stuff ... finally: output.close() But my point still stands, I believe :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On 30/01/2014 06:33, Andrew Berg wrote: On 2014.01.29 23:56, Jessica Ross wrote: I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? My guess would be that the interpreter doesn't let the finally block get skipped under any circumstances, so the return value gets set to True, but then it forces the finally block to be run before returning, which changes the return value to False. Mine too. We can check that the interpreter gets as far as evaluating the return value in the except block: def paradox2(): try: raise Exception(Raise) except: print(Except) return [print(Return), True][1] finally: print(Finally) return False return None ret = paradox2() Except Return Finally ret False -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On 01/30/2014 10:12 AM, Rotwang wrote: On 30/01/2014 06:33, Andrew Berg wrote: On 2014.01.29 23:56, Jessica Ross wrote: I found something like this in a StackOverflow discussion. -- def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... -- return_val = paradox() Except after try Finally -- return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? My guess would be that the interpreter doesn't let the finally block get skipped under any circumstances, so the return value gets set to True, but then it forces the finally block to be run before returning, which changes the return value to False. Mine too. We can check that the interpreter gets as far as evaluating the return value in the except block: -- def paradox2(): try: raise Exception(Raise) except: print(Except) return [print(Return), True][1] finally: print(Finally) return False return None -- ret = paradox2() Except Return Finally -- ret False And just to be thorough, if the finally block doesn't have a return: -- def paradox3(): try: raise Exception(Raise) except: print(Except) return [print(Return), True][1] finally: print(Finally) return None -- print(paradox3()) Except Return Finally True -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On 1/30/2014 7:05 AM, Dave Angel wrote: Jessica Ross deathwea...@gmail.com Wrote in message: I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? The finally has to happen before any return inside the try or the except. And once you're in the finally clause you'll finish it before resuming the except clause. Since it has a return, that will happen before the other returns. The one in the except block will never get reached. It's the only reasonable behavior., to my mind. Checking with the disassembled code, it appears that the except return happens first and is then caught and the value over-written 2 0 SETUP_FINALLY 45 (to 48) 3 SETUP_EXCEPT16 (to 22) 3 6 LOAD_GLOBAL 0 (Exception) 9 LOAD_CONST 1 ('Exception raised during try') 12 CALL_FUNCTION1 (1 positional, 0 keyword pair) 15 RAISE_VARARGS1 18 POP_BLOCK 19 JUMP_FORWARD22 (to 44) 422 POP_TOP 23 POP_TOP 24 POP_TOP 5 25 LOAD_GLOBAL 1 (print) 28 LOAD_CONST 2 ('Except after try') 31 CALL_FUNCTION1 (1 positional, 0 keyword pair) 34 POP_TOP 6 35 LOAD_CONST 3 (True) 38 RETURN_VALUE 39 POP_EXCEPT 40 JUMP_FORWARD 1 (to 44) 43 END_FINALLY 44 POP_BLOCK 45 LOAD_CONST 0 (None) 848 LOAD_GLOBAL 1 (print) 51 LOAD_CONST 4 ('Finally') 54 CALL_FUNCTION1 (1 positional, 0 keyword pair) 57 POP_TOP 9 58 LOAD_CONST 5 (False) 61 RETURN_VALUE 62 END_FINALLY 10 63 LOAD_CONST 0 (None) 66 RETURN_VALUE -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Try-except-finally paradox
I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On Jan 29, 2014 11:01 PM, Jessica Ross deathwea...@gmail.com wrote: I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? The docs don't seem to specify what happens in this case, but this behavior is intuitive to me. If the except suite had raised an exception instead of returning, the return in the finally would suppress that. The generalized rule appears to be that the control flow specification executed later overrides the earlier. -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
On 2014.01.29 23:56, Jessica Ross wrote: I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? My guess would be that the interpreter doesn't let the finally block get skipped under any circumstances, so the return value gets set to True, but then it forces the finally block to be run before returning, which changes the return value to False. -- CPython 3.3.2 | Windows NT 6.2.9200 / FreeBSD 10.0 -- https://mail.python.org/mailman/listinfo/python-list
Re: Try-except-finally paradox
Le jeudi 30 janvier 2014 06:56:16 UTC+1, Jessica Ross a écrit : I found something like this in a StackOverflow discussion. def paradox(): ... try: ... raise Exception(Exception raised during try) ... except: ... print Except after try ... return True ... finally: ... print Finally ... return False ... return None ... return_val = paradox() Except after try Finally return_val False I understand most of this. What I don't understand is why this returns False rather than True. Does the finally short-circuit the return in the except block? The paradox is, in my mind, that the fct paradox() is programmed to be paradoxal. Compare with: def noparadox(i): ... try: ... a = 1 / i ... print('Process') ... except ZeroDivisionError: ... print(ZeroDivisionError) ... a = '?' ... except Exception: ... print(Exception) ... a = '?' ... finally: ... print(Finally) ... return a ... noparadox(2) Process Finally 0.5 noparadox(0) ZeroDivisionError Finally '?' noparadox('asdf') Exception Finally '?' jmf -- https://mail.python.org/mailman/listinfo/python-list