[Python-ideas] except expression

Chris Angelico rosuav at gmail.com
Thu Feb 20 02:48:33 CET 2014


On Thu, Feb 20, 2014 at 12:11 PM, Yury Selivanov
<yselivanov.ml at gmail.com> wrote:
>
> On 2/19/2014, 7:56 PM, Chris Angelico wrote:
>>
>> On Thu, Feb 20, 2014 at 11:22 AM, Yury Selivanov
>>> # set 'value' to 42 if len(a) < 10
>>> # or else, return 'spam'
>>> value = 42 if a[10] raises IndexError else 'spam'
>>
>> Have you a use-case for this? It completely ignores the original
>> expression value.
>
> Something like
>    result = 'failed' if command() raises else 'ok'

Yep, I can see the theory of it. What I mean is, do you have actual
production code that looks like this? Concrete examples are usually
easier to argue based on. How would you currently spell it?

try:
    command()
    result = 'ok'
except SomeException:
    result = 'failed'

Do you have code like that?

Part of the question here is that, if the thing you're testing is
going to have its return value ignored anyway, does it need to be an
expression? I mean, why not do this:

result = 'div by zero' if x += 1/y raises else 'no error'

which would be some serious pain for the parser. But having an
expression that deliberately ignores one of its subexpressions is a
bit weird. We don't usually write this, unless we're going for
obfuscation:

value = (l.append("x"), l)[-1]

Although I could imagine that a MacroPy trick be done to make that
more useful, eg for method chaining:

value = (l.append("x"), l)[-1].append("y")

But for exception handling where you don't care about the value of the
expression, there's already an obvious way to spell it, and that's the
statement form. So I'm looking to see a compelling use-case from
production code that shows the benefit of this notation.

>>> # same as above but if a[10] raises anything
>>> value = 42 if a[10] raises
>>
>> I'm giving this an immediate common-law rejection, as the bare-except
>> sub-proposal has already been rejected.
>
> Since it is a new keyword, we can document that it
> can intercept only Exceptions, not BaseExceptions.

Yes, but overly-broad catching is a big problem even without catching
"Exception..BaseException" (if I may use the git notation here -
meaning "everything reachable from BaseException but not from
Exception"). Earlier in this discussion we proposed having a bare
except catch some specific set of "common exceptions". The results of
that discussion are in the PEP's rejection section; one of the largest
objections doesn't apply here (consistency with the statement form
bare except), but the others do.

>>> # another example
>>> foo(None if dct['key'] raises)
>>
>> And what if it doesn't? Reads nicely for the exceptional case.
>> Presumably it's the value of dct['key'] if it doesn't raise, but
>> that's not obvious from how it reads.
>
> Without this you would need to write:
>    foo(None if dct['key'] raises else dct[key])
>
> Which is code duplication and a performance impact,
> since we'll have to evaluate expression twice.

Right, not to mention a correctness error if the evaluation has side
effects. But if you read it in English, there does need to be an
"else" clause, otherwise you're left with the "And what if it
doesn't?" that I started with. It reads very nicely for the
exceptional case, but much less nicely for the normal case. I don't
dispute the semantics though.

>> My main objection here is that it reads backwards.
>
> Yes, that's understandable.
>
> Although, as you yourself noted, Python has
> 'expr if expr else expr' already. Yes, it is a bit awkward,
> but lots of people (including me) find it very readable and
> easy to understand.

Yes, but is that a good thing? The ternary if is justified because it
reads well in English, but even so, it does trap people. I am
listening to proposals that put the operands in the "wrong order", but
the bar is higher - they have to justify that potential confusion.

> Same with my proposal. If follows the already established
> syntax and reads nicely.
>
> Could you please add to the PEP (in other proposals section?)

It's in there. I split it into two parts: firstly, a nearly-equivalent
proposal that uses the archaic "raise" (as that's already a keyword),
and then a comment underneath about creating a new keyword.

ChrisA


More information about the Python-ideas mailing list