Possible PEP regarding the use of the continue keyword in try/except blocks
I was writing some python code earlier, and I noticed that in a code that looks somwhat like this one : try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e)
"invalid literal for int() with base 10: 'string'"
this code will handle the exception, but the code in the try block will not continue. I propose to be able to use the continue keyword to continue the execution of the try block even when an error is handled. The above could then be changed to : try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e) continue
"invalid literal for int() with base 10: 'string'" "continued on"
On 1/5/19 7:38 PM, Simon wrote:
I was writing some python code earlier, and I noticed that in a code that looks somwhat like this one :
try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e)
"invalid literal for int() with base 10: 'string'"
this code will handle the exception, but the code in the try block will not continue.
I propose to be able to use the continue keyword to continue the execution of the try block even when an error is handled. The above could then be changed to :
try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e) continue
"invalid literal for int() with base 10: 'string'" "continued on"
How would you tell it where to continue? Why would it be the next statement? If you want that then you just need to do it like: try: i = int("string") except ValueError as e: print(e) print("continued on") j = int(9.0) i.e. the try block is the program segment that either executes successful, or your exception routine recovers from the error and sets things up to continue from there. -- Richard Damon
On Sun, Jan 06, 2019 at 01:38:33AM +0100, Simon wrote:
I propose to be able to use the continue keyword to continue the execution of the try block even when an error is handled. The above could then be changed to :
try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e) continue
"invalid literal for int() with base 10: 'string'" "continued on"
That's literally what the except clause is intended for, not the body of the try block. try: i = int("string") except ValueError as e: print(e) print("continued on") j = int(9.0) Putting the error handler in the try block is a serious problem for two reasons: (1) What if an error *doesn't* occur? The error handler occurs anyway: try: i = int("1234") # This succeeds. # and then immediately runs the error handler... oops! print("continued on") j = int(9.0) except ValueError as e: print(e) continue (2) And what happens if the error handler raises an error? The exception is raised, the except clause is called, the continue statement jumps back to the same block of code that just failed and will fail again. And again. And again. Forever. -- Steve
On Sun., 6 Jan. 2019, 13:39 Simon <simon.bordeyne@gmail.com wrote:
I was writing some python code earlier, and I noticed that in a code that looks somwhat like this one :
try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e)
"invalid literal for int() with base 10: 'string'"
this code will handle the exception, but the code in the try block will not continue.
I propose to be able to use the continue keyword to continue the execution of the try block even when an error is handled. The above could then be changed to :
In terms of implementation, I think continue would be problematic while true: try: x = foo() return x except: continue is already valid code. You'd need some way of disambiguating, either a keyword or parameter to continue. Both of which would require a very big benefit for us to do, given the ecosystem impact that such things have.
try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e) continue
"invalid literal for int() with base 10: 'string'" "continued on"
Exception handling is not internally line orientated, so this proposed resume functionality doesn't map exactly. But if the following in the same way as what you envision: def handle(f, *args): try: return f(*args) except ValueError as e: print(e) i = handle( int, "string") handle(print, "continued on") j = handle(int, 9.0) Then I have to say I'm not sure what you are trying to solve. Is it the verbosity? Is it the flow control?
On Sat, Jan 5, 2019 at 4:39 PM Simon <simon.bordeyne@gmail.com> wrote:
I propose to be able to use the continue keyword to continue the execution of the try block even when an error is handled. The above could then be changed to :
try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e) continue
"invalid literal for int() with base 10: 'string'" "continued on"
There is already a much simpler way of doing this: try: i = int("string") except ValueError as e: print(e) print("continued on") j = int(9.0) The point of the 'try' block is to encapsulate the code you want to *stop* executing if an exception is raised. If you want code to be run regardless of whether an exception is raised, move it past the try-except. ~Amber
There is already a much simpler way of doing this:
try: i = int("string") except ValueError as e: print(e) print("continued on") j = int(9.0)
The point of the 'try' block is to encapsulate the code you want to *stop* executing if an exception is raised. If you want code to be run regardless of whether an exception is raised, move it past the try-except.
To be fair, I suspect the issue was there were two calls to int() there that might raise a ValueError, and the OP wanted to catch them with one except, so you would need to do somethign like: try: i = int("string") except ValueError as e: print(e) print("continued on") try: j = int(9.0) except ValueError as e: print(e) Which can seem a bit verbose, but in fact, there are a number of ways one might want to proceed with/without an error, and the current except, finally, else options cover them all in a clearly defined way. -CHB
~Amber _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
I knew that you can just chain try/except blocks, and it's how I do it now, but the example I provided wasn't very realistic. Take for example the initialization of a class from a config file, config file which may or may not have certain keys in it. With many keys, it is very inconvenient to chain try/except blocks to handle every possible case. Having the continue keyword would prove useful to put several error prone lines of code into a single try block, and have the execution continue as normal at tge statement after the statement errored out Envoyé depuis mon smartphone Samsung Galaxy. -------- Message d'origine --------De : Amber Yust <amber.yust@gmail.com> Date : 06/01/2019 09:07 (GMT+01:00) À : Simon <simon.bordeyne@gmail.com> Cc : python-ideas@python.org Objet : Re: [Python-ideas] Possible PEP regarding the use of the continue keyword in try/except blocks On Sat, Jan 5, 2019 at 4:39 PM Simon <simon.bordeyne@gmail.com> wrote:I propose to be able to use the continue keyword to continue the execution of the try block even when an error is handled. The above could then be changed to : try: i = int("string") print("continued on") j = int(9.0) except ValueError as e: print(e) continue
"invalid literal for int() with base 10: 'string'">>> "continued on" There is already a much simpler way of doing this: try: i = int("string") except ValueError as e: print(e) print("continued on") j = int(9.0) The point of the 'try' block is to encapsulate the code you want to *stop* executing if an exception is raised. If you want code to be run regardless of whether an exception is raised, move it past the try-except. ~Amber
On 1/6/19 9:54 PM, simon.bordeyne wrote:
I knew that you can just chain try/except blocks, and it's how I do it now, but the example I provided wasn't very realistic.
Take for example the initialization of a class from a config file, config file which may or may not have certain keys in it. With many keys, it is very inconvenient to chain try/except blocks to handle every possible case. Having the continue keyword would prove useful to put several error prone lines of code into a single try block, and have the execution continue as normal at tge statement after the statement errored out
For something like reading options from a config file, I would use a call that specifies the key and a value to use if the key isn't present, and inside that function I might use a try to handle any exception caused when processing the key, and it could return the default. For your case, it is hard to imagine what you could put in the except block to handle the error, as you have no idea which key threw the error, so you have no idea which key needs to be fixed. Also, what happens if the exception is thrown inside a function that is called, do you return to the next line of that function, or the next line after the function call? What happens if the exception happens inside a loop (that is inside the try)? Do you just go to the next instruction in the loop and continue looping? -- Richard Damon
I think the main issue is this: exception handling is already problematic with its nonlocal transfer of control. Making it bidirectional makes code even more difficult to understand. State will change "under your feet" without any syntactic clue. In "The Design and Evolution of C++" Bjarne Stroustroup quotes an engineer working on a large system using such a feature extensively ; they ended up having to rewrite every single occurrence of it because it introduced a huge amounts of bugs. This is the reason C++ does not support resume semantics. Newer languages go in the direction of avoiding exceptions altogether, not adding more intricate control flow directives. This proposal is basically about introducing goto to the language. Elazar בתאריך יום ב׳, 7 בינו׳ 2019, 5:07, מאת Richard Damon < Richard@damon-family.org>:
On 1/6/19 9:54 PM, simon.bordeyne wrote:
I knew that you can just chain try/except blocks, and it's how I do it now, but the example I provided wasn't very realistic.
Take for example the initialization of a class from a config file, config file which may or may not have certain keys in it. With many keys, it is very inconvenient to chain try/except blocks to handle every possible case. Having the continue keyword would prove useful to put several error prone lines of code into a single try block, and have the execution continue as normal at tge statement after the statement errored out
For something like reading options from a config file, I would use a call that specifies the key and a value to use if the key isn't present, and inside that function I might use a try to handle any exception caused when processing the key, and it could return the default.
For your case, it is hard to imagine what you could put in the except block to handle the error, as you have no idea which key threw the error, so you have no idea which key needs to be fixed.
Also, what happens if the exception is thrown inside a function that is called, do you return to the next line of that function, or the next line after the function call?
What happens if the exception happens inside a loop (that is inside the try)? Do you just go to the next instruction in the loop and continue looping?
-- Richard Damon
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
This proposal is basically about introducing goto to the language.
A bit hyperbolic but I agree that it has the same problem as goto. But the specific suggested solution is not something we should be restricted so rigidly to in this discussion. One could for example see another solution to the same problem: with supress_raise(TypeError, ValueError): do_the_things() I have no idea how to actually implement this though and it's also a bad idea but I think we should first find the best idea to solve the underlying pain point then talk about rejecting or supporting that. / Anders
On Mon, Jan 7, 2019 at 7:11 PM Anders Hovmöller <boxed@killingar.net> wrote:
This proposal is basically about introducing goto to the language.
A bit hyperbolic but I agree that it has the same problem as goto. But the specific suggested solution is not something we should be restricted so rigidly to in this discussion. One could for example see another solution to the same problem:
with supress_raise(TypeError, ValueError): do_the_things()
I have no idea how to actually implement this though and it's also a bad idea but I think we should first find the best idea to solve the underlying pain point then talk about rejecting or supporting that.
You mean like this? https://docs.python.org/3/library/contextlib.html#contextlib.suppress ChrisA
You mean like this?
https://docs.python.org/3/library/contextlib.html#contextlib.suppress
Hah. Exactly. Maybe that is what the OP wanted in the first place? It's always surprising how much stuff is in the standard lib even after all these years! Thanks for this. / Anders
On Mon, 7 Jan 2019 at 09:27, Chris Angelico <rosuav@gmail.com> wrote:
On Mon, Jan 7, 2019 at 7:11 PM Anders Hovmöller <boxed@killingar.net> wrote:
This proposal is basically about introducing goto to the language.
A bit hyperbolic but I agree that it has the same problem as goto. But the specific suggested solution is not something we should be restricted so rigidly to in this discussion. One could for example see another solution to the same problem:
with supress_raise(TypeError, ValueError): do_the_things()
I have no idea how to actually implement this though and it's also a bad idea but I think we should first find the best idea to solve the underlying pain point then talk about rejecting or supporting that.
You mean like this?
https://docs.python.org/3/library/contextlib.html#contextlib.suppress
That doesn't do what the OP requested. It suppresses errors from the outside but doesn't resume execution in the block so e.g.: a = b = None with suppress(ValueError): a = float(str_a) b = float(str_b) The OP wants the the b= line to execute even if the a= line raises an exception. -- Oscar
On Mon, Jan 7, 2019 at 11:11 PM Oscar Benjamin <oscar.j.benjamin@gmail.com> wrote:
On Mon, 7 Jan 2019 at 09:27, Chris Angelico <rosuav@gmail.com> wrote:
On Mon, Jan 7, 2019 at 7:11 PM Anders Hovmöller <boxed@killingar.net> wrote:
This proposal is basically about introducing goto to the language.
A bit hyperbolic but I agree that it has the same problem as goto. But the specific suggested solution is not something we should be restricted so rigidly to in this discussion. One could for example see another solution to the same problem:
with supress_raise(TypeError, ValueError): do_the_things()
I have no idea how to actually implement this though and it's also a bad idea but I think we should first find the best idea to solve the underlying pain point then talk about rejecting or supporting that.
You mean like this?
https://docs.python.org/3/library/contextlib.html#contextlib.suppress
That doesn't do what the OP requested. It suppresses errors from the outside but doesn't resume execution in the block so e.g.:
a = b = None with suppress(ValueError): a = float(str_a) b = float(str_b)
The OP wants the the b= line to execute even if the a= line raises an exception.
True, but what the OP actually asked for is basically impossible. And at least you can write: with suppress(ValueError): a = float(str_a) with suppress(ValueError): b = float(str_b) which is a heap less noisy than the explicit try/except. ChrisA
On 1/7/2019 10:15 AM, Chris Angelico wrote:
On Mon, Jan 7, 2019 at 11:11 PM Oscar Benjamin <oscar.j.benjamin@gmail.com> wrote:
On Mon, 7 Jan 2019 at 09:27, Chris Angelico <rosuav@gmail.com> wrote:
On Mon, Jan 7, 2019 at 7:11 PM Anders Hovmöller <boxed@killingar.net> wrote:
This proposal is basically about introducing goto to the language. A bit hyperbolic but I agree that it has the same problem as goto. But the specific suggested solution is not something we should be restricted so rigidly to in this discussion. One could for example see another solution to the same problem:
with supress_raise(TypeError, ValueError): do_the_things()
I have no idea how to actually implement this though and it's also a bad idea but I think we should first find the best idea to solve the underlying pain point then talk about rejecting or supporting that.
You mean like this?
https://docs.python.org/3/library/contextlib.html#contextlib.suppress That doesn't do what the OP requested. It suppresses errors from the outside but doesn't resume execution in the block so e.g.:
a = b = None with suppress(ValueError): a = float(str_a) b = float(str_b)
The OP wants the the b= line to execute even if the a= line raises an exception.
True, but what the OP actually asked for is basically impossible. And at least you can write:
with suppress(ValueError): a = float(str_a) with suppress(ValueError): b = float(str_b)
which is a heap less noisy than the explicit try/except.
I think the OP was asking for a construct to automatically wrap every statement in a suppress context manager. Which is probably possible, but I think a bad idea. As a third party solution, maybe some creative AST manipulations could do the trick if someone were so inclined. Eric
On 7 Jan 2019, at 03:06, Richard Damon <Richard@damon-family.org> wrote:
For something like reading options from a config file, I would use a call that specifies the key and a value to use if the key isn't present, and inside that function I might use a try to handle any exception caused when processing the key, and it could return the default.
Most config file APIs I have used have has_section and has_key type functions that remove the need to catch exceptions. What config file API are you using htat is missing this? Barry
On 1/7/19 3:38 PM, Barry wrote:
On 7 Jan 2019, at 03:06, Richard Damon <Richard@damon-family.org> wrote:
For something like reading options from a config file, I would use a call that specifies the key and a value to use if the key isn't present, and inside that function I might use a try to handle any exception caused when processing the key, and it could return the default. Most config file APIs I have used have has_section and has_key type functions that remove the need to catch exceptions.
What config file API are you using htat is missing this?
Barry
I was talking about if I was to roll my own, I would start by calling a function I was writing with the key / default value, and it might have a try block so any error that threw an exception would cause it to fall back to the default value. The OP is obviously obviously thinking of something a bit off standard, or he would just be using a standard config reader, and not need this. Maybe the issue is parsing the data from the config line into some internal format, and wanting to catch bad values, like a line that said "nfiles = 42balloons" that throws when it is expecting just a number. -- Richard Damon
participants (13)
-
Amber Yust
-
Anders Hovmöller
-
Barry
-
Chris Angelico
-
Chris Barker
-
Elazar
-
Eric V. Smith
-
Oscar Benjamin
-
Richard Damon
-
Robert Collins
-
Simon
-
simon.bordeyne
-
Steven D'Aprano