suggestion for try/except program flow
In this situation, which happens to me fairly frequently... try: try: raise Cheese except Cheese, e: # handle cheese raise except: # handle all manner of stuff, including cheese ...it would be nice (& more readable) if one were able to recatch a named exception with the generic (catch-all) except clause of its own try, something like this: try: raise Cheese except Cheese, e: # handle cheese recatch except: # handle all manner of stuff, including cheese
On Sat, Mar 28, 2009 at 5:06 AM, Mark Donald <foobarmus@gmail.com> wrote:
In this situation, which happens to me fairly frequently...
try: try: raise Cheese except Cheese, e: # handle cheese raise except: # handle all manner of stuff, including cheese
...it would be nice (& more readable) if one were able to recatch a named exception with the generic (catch-all) except clause of its own try, something like this:
try: raise Cheese except Cheese, e: # handle cheese recatch except: # handle all manner of stuff, including cheese
I'm not sure recatch is all that more reasonable -- it's another fairly obscure control flow verb. I think the current situation isn't so bad. Nick already pointed out an idiom for doing this without two try clauses: except BaseException as e: if isinstance(e, Cheese): # handle cheese # handle all manner of stuff, including cheese -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Unless something has changed in Python 3+, I believe Nick's idiom requires the generic handler code to be copied into a second except clause to achieve identical behaviour, as follows... except BaseException as e: if isinstance(e, Cheese): # handle cheese # handle all manner of stuff, including cheese except: # handle all manner of OTHER stuff in the same way ...which makes the nested try block more semantic. This can be tested by putting > raise "this is deprecated..." into the try block, which generates an error that is NOT caught by "except BaseException" however IS caught by "except". I realise that "recatch" may seem like a trivial suggestion, but I believe it would be a slight improvement, which means it's not trivial. Try/except statements are supposedly preferential to "untried" if statements that handle isolated cases, but if statements are a lot easier to imagine, so people use them all them time - style be damned. Each slight improvement in try/except is liable to make it more attractive to coders, the end result being better code (for example, the implementation of PEP 341 increased my team's use of try/except significantly, causing a huge improvement to code readability). Imagine if you could do this: runny = True runnier_than_you_like_it = False raise Cheese except Cheese, e # handle cheese if runny: recatch as Camembert except Camembert, e # handle camembert if runnier_than_you_like_it: recatch else: uncatch # ie, else clause will be effective... except: # not much of a cheese shop, really is it? else: # negotiate vending of cheesy comestibles finally: # sally forth And, I'm not trying to be belligerent here, but before somebody says... Cheese(Exception) Camembert(Cheese) ...just please have a little think about it. Mark 2009/3/28 Guido van Rossum <guido@python.org>:
On Sat, Mar 28, 2009 at 5:06 AM, Mark Donald <foobarmus@gmail.com> wrote:
In this situation, which happens to me fairly frequently...
try: try: raise Cheese except Cheese, e: # handle cheese raise except: # handle all manner of stuff, including cheese
...it would be nice (& more readable) if one were able to recatch a named exception with the generic (catch-all) except clause of its own try, something like this:
try: raise Cheese except Cheese, e: # handle cheese recatch except: # handle all manner of stuff, including cheese
I'm not sure recatch is all that more reasonable -- it's another fairly obscure control flow verb. I think the current situation isn't so bad. Nick already pointed out an idiom for doing this without two try clauses:
except BaseException as e: if isinstance(e, Cheese): # handle cheese # handle all manner of stuff, including cheese
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Sat, Mar 28, 2009 at 9:54 AM, Mark Donald <foobarmus@gmail.com> wrote:
Unless something has changed in Python 3+, I believe Nick's idiom requires the generic handler code to be copied into a second except clause to achieve identical behaviour, as follows...
except BaseException as e: if isinstance(e, Cheese): # handle cheese # handle all manner of stuff, including cheese except: # handle all manner of OTHER stuff in the same way
In 3.0, the second except clause is unreachable because all exceptions inherit from BaseException.
...which makes the nested try block more semantic. This can be tested by putting > raise "this is deprecated..." into the try block, which generates an error that is NOT caught by "except BaseException" however IS caught by "except".
I realise that "recatch" may seem like a trivial suggestion, but I believe it would be a slight improvement, which means it's not trivial. Try/except statements are supposedly preferential to "untried" if statements that handle isolated cases, but if statements are a lot easier to imagine, so people use them all them time - style be damned. Each slight improvement in try/except is liable to make it more attractive to coders, the end result being better code (for example, the implementation of PEP 341 increased my team's use of try/except significantly, causing a huge improvement to code readability).
Imagine if you could do this:
runny = True runnier_than_you_like_it = False raise Cheese except Cheese, e # handle cheese if runny: recatch as Camembert except Camembert, e # handle camembert if runnier_than_you_like_it: recatch else: uncatch # ie, else clause will be effective... except: # not much of a cheese shop, really is it? else: # negotiate vending of cheesy comestibles finally: # sally forth
And, I'm not trying to be belligerent here, but before somebody says...
Cheese(Exception) Camembert(Cheese)
...just please have a little think about it.
Mark
2009/3/28 Guido van Rossum <guido@python.org>:
On Sat, Mar 28, 2009 at 5:06 AM, Mark Donald <foobarmus@gmail.com> wrote:
In this situation, which happens to me fairly frequently...
try: try: raise Cheese except Cheese, e: # handle cheese raise except: # handle all manner of stuff, including cheese
...it would be nice (& more readable) if one were able to recatch a named exception with the generic (catch-all) except clause of its own try, something like this:
try: raise Cheese except Cheese, e: # handle cheese recatch except: # handle all manner of stuff, including cheese
I'm not sure recatch is all that more reasonable -- it's another fairly obscure control flow verb. I think the current situation isn't so bad. Nick already pointed out an idiom for doing this without two try clauses:
except BaseException as e: if isinstance(e, Cheese): # handle cheese # handle all manner of stuff, including cheese
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
Mark Donald wrote:
Unless something has changed in Python 3+, I believe Nick's idiom requires the generic handler code to be copied into a second except clause to achieve identical behaviour, as follows...
Guido already said this, but yes, something did change in 3.0: unlike the 2.x series, the raise statement in 3.x only accepts instances of BaseException, so having both an "except BaseException:" clause and a bare "except:" clause becomes redundant. Running 2.x code with the -3 flag to enable Py3k deprecation warnings actually points this out whenever a non-instance of BaseException is raised. 'Normal' exceptions are encouraged to inherit from Exception, with only 'terminal' exceptions (currently only SystemExit, GeneratorExit, KeyboardInterrupt) outside that heirarchy. I agree that in 2.x, this means that if you want to handle non-Exception exceptions along with well-behaved exceptions, you need to use sys.exc_info() to adapt my previous example: except: _et, e, _tb = sys.exc_info() if isinstance(e, Cheese): # handle cheese # handle all manner of stuff, including cheese Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Guido already said this, but yes, something did change in 3.0: unlike the 2.x series, the raise statement in 3.x only accepts instances of BaseException, so having both an "except BaseException:" clause and a bare "except:" clause becomes redundant.
Ah, apologies... I need to update myself. 'uncatch' to subsequently execute the else clause is still going to be impossible, but I don't have a real-world need for that as yet. Cheers
Mark Donald wrote:
Guido already said this, but yes, something did change in 3.0: unlike the 2.x series, the raise statement in 3.x only accepts instances of BaseException, so having both an "except BaseException:" clause and a bare "except:" clause becomes redundant.
Ah, apologies... I need to update myself.
'uncatch' to subsequently execute the else clause is still going to be impossible, but I don't have a real-world need for that as yet.
If you really find yourself doing this kind of exception interrogation a lot, you may find it easier to do it in the __exit__ method of a context manager. Those are *always* invoked regardless of how the with statement ends and you can then do whatever flow control you like based on the type of the first argument (and whether or not it is None). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
participants (3)
-
Guido van Rossum
-
Mark Donald
-
Nick Coghlan