On 13/02/2014 12:50, Nick Coghlan wrote:
On 13.02.2014 10:24, Nick Coghlan wrote:
General comment: like Raymond, I'm inclined to favour a nice expression friendly exception handling syntax, precisely because of the proliferation of relatively ad hoc alternative solutions (in particular, the popularity of being able to pass in default values to handle empty iterables). Here's a variant the resembles the code you'd write in a helper function to achieve the same thing, only stripped down somewhat:
x = something() except ValueError return default_value
def try_something(): try: return something() except ValueError: return default_value
x = something() except ValueError as exc return exc.message
def try_something(): try: return something() except ValueError as exc return exc.message
Obviously, having a keyword "use" would make a better fit :-)
x = something() except ValueError use default_value Even if we don't agree on a resolution for 3.5, I think there's more
On 13 February 2014 20:10, M.-A. Lemburg
wrote: than enough interest for it to be worth someone's while to collate some of the proposals in a PEP - if nothing else, it will save rehashing the whole discussion next time it comes up :) The benefits of this:
- the status quo is that various APIs are growing "default" parameters to handle the case where they would otherwise throw an exception - this is creating inconsistencies, as some such functions can be used easily as expressions without risking any exception (those where such a parameter has been added), as well as a temptation to use "Look Before You Leap" pre-checks, even in cases where exception handling would be a better choice - sequence indexing is a case where there is no current standard mechanism for providing a default value, so you're either use a pre-check for the system length, or else using a full try statement or context manager to handle the IndexError - by providing a clean, expression level syntax for handling a single except clause and providing an alternate value for the expression, this problem could be solved once and for all in a systematic way, rather than needing to incrementally change the API of a variety of functions (as well as addressing the container subscripting case in a way that doesn't require switching away from using the subscript syntax to a normal function call, or switching from use an expression to a statement)
Some of the specific syntactic proposals:
x = op() except default if Exception x = op() except default for Exception x = op() except default from Exception x = op() except Exception return default
x = op() except exc.attr if Exception as exc x = op() except exc.attr for Exception as exc x = op() except exc.attr from Exception as exc x = op() except Exception as exc return exc.attr
The except/if construct has parser ambiguity issues. While they're potentially solvable by requiring parens around conditional expressions in that context, that would come at the cost of a significant redesign of the language grammar.
The except/for option reads quite nicely, but introduces a substantially different meaning for "for".
The except/from option reads OK when combined with "as" and actually using the caught exception, but otherwise reads strangely.
The except/return option looks like it should either introduce a new scope or else return from the current function. The presence of the "as exc" clause in all variants actually suggests a new scope could be a good idea, given past experience with iteration variables in list comprehensions.
So, if we take the point of view that the new syntax is almost *literally* a shorthand for:
def _helper(op, exc, make_default): try: return op() except exc: return make_default()
x = _helper(op, Exception, make_default)
Then that would suggest the following syntax and interpretation:
op() except Exception pass
def _work_or_return_None(): try: return op() except Exception: pass _work_or_return_None()
x = op() except Exception return value
def _work_or_return_default(): try: return op() except Exception: return value x = _work_or_return_default()
x = op() except Exception as exc return exc.attr
def _work_or_process_exception(): try: return op() except Exception as exc: return exc.attr x = _work_or_process_exception()
OK, with the "introduces a new scope" caveat, consider me a fan of MAL's syntax unless/until someone points out a potential flaw that I have missed.
A possible addition: allow "raise" in addition to "pass" and "return" (for exception transformation as an expression)
Cheers, Nick.
It certainly feels right for the order to be normal value, exception, default value. So the syntax I would like is x = entries[0] except IndexError XXX None where XXX is some keyword. Ideally 'then' or perhaps 'when' which read better than 'else', but I understand adding a new keyword is a big deal. (FWIW I also wish trinary expressions were written as if condition then value-if-true else value-if-false which to me reads better than the status quo, but that ship has sailed.) Rob Cliffe