[Python-ideas] except expression

Rob Cliffe rob.cliffe at btinternet.com
Thu Feb 13 14:26:57 CET 2014


On 13/02/2014 12:50, Nick Coghlan wrote:
> On 13 February 2014 20:10, M.-A. Lemburg <mal at egenix.com> 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
> 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


More information about the Python-ideas mailing list