except expression

121 views
Skip to first unread message

Ram Rachum

unread,
Feb 12, 2014, 4:02:57 PM2/12/14
to python...@googlegroups.com
Hi,

Here's an idea that would help shortening code. Allow a ternary expression based on except, like so:

    first_entry = entries[0] except IndexError else None
    item = my_queue.get() except queue.Empty else None
    response_text = request('http://whatever.com').text except HttpError else "Can't access data"

Aside from the fact that this would be a big grammar addition, a big problem here is the usage of the `else` keyword, that when used with except usually means "what would happen if there wasn't an exception" and here means the opposite. But I couldn't think of a nicer syntax.

I realize that this is a big change and that most people would be opposed to this... But I guess I just wanted to share my idea :)



Ram.

Paul Moore

unread,
Feb 12, 2014, 5:00:20 PM2/12/14
to Ram Rachum, Python-Ideas
On 12 February 2014 21:02, Ram Rachum <ram.r...@gmail.com> wrote:
> I realize that this is a big change and that most people would be opposed to
> this... But I guess I just wanted to share my idea :)

This was discussed a while ago on the list. I can't find the thread
right now, but you may want to search the archives.
Paul

PS Looks like posting via google groups not only breaks filtering and
threading, it also breaks reply-all (as I can't post to the google
group). Could you please post direct to the group rather than through
the google groups interface? Thanks.
_______________________________________________
Python-ideas mailing list
Python...@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

MRAB

unread,
Feb 12, 2014, 6:56:02 PM2/12/14
to python...@python.org
On 2014-02-12 21:02, Ram Rachum wrote:
> Hi,
>
> Here's an idea that would help shortening code. Allow a ternary
> expression based on except, like so:
>
> first_entry = entries[0] except IndexError else None
> item = my_queue.get() except queue.Empty else None
> response_text = request('http://whatever.com').text except HttpError else "Can't access data"
>
> Aside from the fact that this would be a big grammar addition, a big
> problem here is the usage of the `else` keyword, that when used with
> except usually means "what would happen if there wasn't an exception"
> and here means the opposite. But I couldn't think of a nicer syntax.
>
If you don't mind having a colon in the middle of an expression:

first_entry = entries[0] except IndexError: None
item = my_queue.get() except queue.Empty: None
response_text = request('http://whatever.com').text except
HttpError: "Can't access data"

What would its precedence be? Maybe it would apply to the preceding
expression or subexpression:

total = (entries[0] except IndexError: 0) + (entries[-1] except
IndexError: 0)

> I realize that this is a big change and that most people would be
> opposed to this... But I guess I just wanted to share my idea :)
>

Raymond Hettinger

unread,
Feb 12, 2014, 7:08:01 PM2/12/14
to Ram Rachum, python-ideas Ideas, python...@googlegroups.com
I would like to see something like this come to fruition.
We need a clean way to express the idea of "take an
arbitrary, exception-raising function and give it a default
argument".

Hopefully, this would end the gradual but never-ending requests
to bloat APIs with "default" arguments.   For example, if your idea
or some variant had been in place, the min() and max() functions
likely wouldn't have grown complex signatures in Python 3.4.


Raymond

Ram Rachum

unread,
Feb 12, 2014, 7:09:53 PM2/12/14
to python...@googlegroups.com
I agree, the colon version is better.

I understand the parsing problem. I don't have a solution, except forcing people to use parentheses when things are ambiguous.

--

--- You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/python-ideas/ZoBGdwuH3uk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to python-ideas+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Ben Finney

unread,
Feb 12, 2014, 7:14:12 PM2/12/14
to python...@python.org
Ram Rachum <ram.r...@gmail.com> writes:

> Here's an idea that would help shortening code. Allow a ternary
> expression based on except, like so:
>
> first_entry = entries[0] except IndexError else None
> item = my_queue.get() except queue.Empty else None
> response_text = request('http://whatever.com').text except HttpError else "Can't access data"

That is more obscure, to my eye, than laying out the control branches:

first_entry = entries[0] except IndexError else None
item = my_queue.get() except queue.Empty else None

try:


response_text = request('http://whatever.com').text

except HttpError:
"Can't access data"

Do you have some real-use code that your proposal would significantly
improve? I find your example to support the refusal of that syntax.

--
\ “The whole area of [treating source code as intellectual |
`\ property] is almost assuring a customer that you are not going |
_o__) to do any innovation in the future.” —Gary Barnett |
Ben Finney

Ram Rachum

unread,
Feb 12, 2014, 7:14:45 PM2/12/14
to Raymond Hettinger, python-ideas Ideas, python...@googlegroups.com
I'm happy you're for it. Maybe one day we'll see a Python 4 with no second argument to dict.get, getattr and so many others...

Ben Finney

unread,
Feb 12, 2014, 7:28:42 PM2/12/14
to python...@python.org
Ben Finney <ben+p...@benfinney.id.au> writes:

> Ram Rachum <ram.r...@gmail.com> writes:
>
> > Here's an idea that would help shortening code. Allow a ternary
> > expression based on except, like so:
> >
> > first_entry = entries[0] except IndexError else None
> > item = my_queue.get() except queue.Empty else None
> > response_text = request('http://whatever.com').text except HttpError else "Can't access data"
>
> That is more obscure, to my eye, than laying out the control branches:

Sorry, I failed to address your first two examples.

I am +0 on the proposal to have something similar to Perl's fallback
syntax, “$foo = bar() or some_default_value”.

Yet I still find the proposed syntax less readable for anything but a
trivial *and* brief case. For anything longer than a few dozen
characters, I still prefer::

try:
response_text = request('http://whatever.com').text
except HttpError:
"Can't access data"

for being explicit and clarifying what to expect.

--
\ “I wish there was a knob on the TV to turn up the intelligence. |
`\ There's a knob called ‘brightness’ but it doesn't work.” |
_o__) —Eugene P. Gallagher |

Andrew Barnert

unread,
Feb 12, 2014, 8:52:36 PM2/12/14
to Ben Finney, python...@python.org
From: Ben Finney <ben+p...@benfinney.id.au>

Sent: Wednesday, February 12, 2014 4:28 PM


> Subject: Re: [Python-ideas] except expression


>
> Ben Finney <ben+p...@benfinney.id.au> writes:
>
>> Ram Rachum <ram.r...@gmail.com> writes:
>>
>> > Here's an idea that would help shortening code. Allow a ternary
>> > expression based on except, like so:
>> >
>> >    first_entry = entries[0] except IndexError else None
>> >    item = my_queue.get() except queue.Empty else None
>> >    response_text = request('http://whatever.com').text except
> HttpError else "Can't access data"
>>
>> That is more obscure, to my eye, than laying out the control branches:
>
> Sorry, I failed to address your first two examples.
>
> I am +0 on the proposal to have something similar to Perl's fallback
> syntax, “$foo = bar() or some_default_value”.

Although this looks nicer than the original proposal, it loses the ability to specify what exception you want to catch. And I think it would be reasonable to want to, e.g., handle queue.Empty but not swallow an AttributeError caused by a typo… On the other hand, I really dislike the misuse of else in the original version. But the syntax can be bikeshedded, and probably has been before.

I have one reservation: Given that so many functions in Python take a "default value" parameter, could this lead to making the language less predictable and consistent? For some expressions, you write "d.get(key, defval)", while for others you write "d.get(key) except KeyError else defval", and it may not be obvious which are which. And I don't think the answer is to remove all those default values. The d.get(key, defval) is much more concise and a bit more readable, and removes the opportunity to, e.g., screw up and use the wrong exception type.

But other than that, if someone can come up with a readable way to write it, I like the idea.

> Yet I still find the proposed syntax less readable for anything but a
> trivial *and* brief case.

I agree—but the same is true for pretty much all expression syntax, and most of it is rarely misused.

Consider if-else ternary expressions. It's very easy to make your code completely unreadable by chaining them together, or using complex test expressions, or using them in the middle of a comprehension, etc. But you rarely see such code. And meanwhile, you see a lot of code that's more concise and readable because it uses trivial if expressions. I think that except expressions would go the same way.

> For anything longer than a few dozen

> characters, I still prefer::
>
>     try:
>         response_text = request('http://whatever.com').text
>     except HttpError:
>         "Can't access data"

> for being explicit and clarifying what to expect.


Except that you're not doing the same thing as the original; you're just evaluating and throwing away the string literal, and not assigning anything to response_text. Having to write "response_text = " twice gives you twice as many places to screw up—as evidenced by the fact that you did so. The exact same thing happens with if statements vs. if expressions, and in fact I think that's one of the reasons people like if expressions.

ru...@yahoo.com

unread,
Feb 12, 2014, 9:49:18 PM2/12/14
to python...@googlegroups.com
On Wednesday, February 12, 2014 3:00:20 PM UTC-7, Paul Moore wrote:
On 12 February 2014 21:02, Ram Rachum <ram.r...@gmail.com> wrote:
[...]

PS Looks like posting via google groups not only breaks filtering and
threading, it also breaks reply-all (as I can't post to the google
group). Could you please post direct to the group rather than through
the google groups interface? Thanks.

There is no need for you to explicitly reply to Google Groups -- it is
gatewayed to the ideas list.  Here is a link to your post on GG:
  https://groups.google.com/d/msg/python-ideas/ZoBGdwuH3uk/49PE5ufVHYAJ
Many people find GG convenient and prefer to use it.



 

Amber Yust

unread,
Feb 12, 2014, 10:08:14 PM2/12/14
to Andrew Barnert, Ben Finney, python...@python.org

Why not use yield instead of else?

foo = something() except BazException yield "bar"

Chris Angelico

unread,
Feb 12, 2014, 10:16:00 PM2/12/14
to python-ideas
On Thu, Feb 13, 2014 at 2:08 PM, Amber Yust <amber...@gmail.com> wrote:
> Why not use yield instead of else?
>
> foo = something() except BazException yield "bar"

yield is already an expression. It'd be theoretically and
syntactically valid (if a little weird) to use yield "bar" in place of
the name BazException; you'd yield "bar" to your caller, then whatever
exception gets sent in would be the one tested for. I honestly cannot
conceive of any situation where this would actually be useful, but it
does make it a little tricky to reuse that keyword :)

ChrisA

Amber Yust

unread,
Feb 12, 2014, 10:20:03 PM2/12/14
to Chris Angelico, python-ideas

Ah, that's a good point (the two-directionality of yield had slipped my mind). I had considered suggesting return instead of yield, which wouldn't have that problem, but it felt like return would be more confusing to see in a context where it doesn't actually return from the enclosing scope.

Amber Yust

unread,
Feb 12, 2014, 10:25:50 PM2/12/14
to Chris Angelico, python-ideas

Another possible option:

foo = something() except None for BarException

With possible support for:

foo = something() except e.message for BarException as e

Chris Angelico

unread,
Feb 12, 2014, 10:38:24 PM2/12/14
to python-ideas
On Thu, Feb 13, 2014 at 2:20 PM, Amber Yust <amber...@gmail.com> wrote:
> Ah, that's a good point (the two-directionality of yield had slipped my
> mind). I had considered suggesting return instead of yield, which wouldn't
> have that problem, but it felt like return would be more confusing to see in
> a context where it doesn't actually return from the enclosing scope.

Yeah. I like the parallel with "get this unless it's empty in which
case use this default", but the 'or' keyword is already a bit awkward
there, so I don't want to advocate that.

name = input("Name [Anonymous]: ") or "Anonymous"
phone = addressbook[name] except KeyError or "Unknown"

It's a nice parallel, but doesn't read well (plus, >> KeyError or
"Unknown" << is already an expression).

+1 on the feature but it definitely needs a syntax that makes sense.
Of course, it could be done as a function call:

def catch(callme, catchme, returnme):
try:
return callme()
except catchme:
return returnme

phone = catch(lambda: addressbook[name], KeyError, "Unknown")

but that's *really* clunky.

Antony Lee

unread,
Feb 13, 2014, 12:46:37 AM2/13/14
to Amber Yust, python-ideas
Even more generally (not sure allowing multiple clauses is a good idea but at least "if" sounds better than "for", I think.
foo = bar() except e.attr1 if FooException as e else e.attr2 if BarException as e

Antony Lee

Amber Yust

unread,
Feb 13, 2014, 12:53:39 AM2/13/14
to anton...@berkeley.edu, ros...@gmail.com, python...@python.org
That has a potential conflict in parsing, however, since the if-else ternary already exists. Yes, the 'as' theoretically disambiguates it for the machine parser, but for a human trying to parse it as they read, it's not nearly as simple.

The reason why I suggested 'for' is that it still flows somewhat naturally - it's using "for" in the sense of "associated with" or "in the place of". "I'll give you my None for your FooException."

Nick Coghlan

unread,
Feb 13, 2014, 4:24:59 AM2/13/14
to Amber Yust, python...@python.org

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).

One use case, for example, is handing IndexError when retrieving an item from a sequence (which currently has no nice standard spelling, and isn't amenable to the "pass in a default answer" solution because it isn't a normal function call).

Another case not handled well by the status quo is when the default answer is expensive to calculate for some reason, so you really only want to calculate it if you actually need it.

Unfortunately, like PEP 308 before it, the hard part is coming up with a reasonable spelling that won't have people breaking out the torches and pitchforks if the PEP is accepted.

On 13 Feb 2014 13:34, "Amber Yust" <amber...@gmail.com> wrote:
>
> Another possible option:
>
> foo = something() except None for BarException
>
> With possible support for:
>
> foo = something() except e.message for BarException as e

This is also one of the possible spellings I came up with, and it is my current least disliked option. The main concern I have with it is the substantially different interpretation it gives to the "for" keyword - as far as is practical, we try to ensure that a given keyword relates to a consistent concept, and the link to iteration is rather tenuous here (it's only present in the fact you can use an iterable of exception types rather than just one). Aside from that concern, I think it scores well on the readability front.

"if" would be better, but, as you already noted, poses significant parsing challenges (since it likely wouldn't be easy to require that ternary expressions use parentheses in this new construct, but still allow the parentheses to be omitted in the general case).

Cheers,
Nick.

Nick Coghlan

unread,
Feb 13, 2014, 4:28:49 AM2/13/14
to Amber Yust, python...@python.org

"from" is another keyword choice worth considering here - that already has no strong semantics of its own ("from x import y" and "yield from iter" derive their meaning from the other keyword involved)

Cheers,
Nick.

>
> Cheers,
> Nick.

M.-A. Lemburg

unread,
Feb 13, 2014, 5:10:40 AM2/13/14
to Nick Coghlan, Amber Yust, python...@python.org
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

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Feb 13 2014)
>>> Python Projects, Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope/Plone.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________
2014-02-12: Released mxODBC.Connect 2.0.4 ... http://egenix.com/go53

::::: Try our mxODBC.Connect Python Database Interface for free ! ::::::

eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
http://www.egenix.com/company/contact/

spir

unread,
Feb 13, 2014, 5:39:00 AM2/13/14
to python...@python.org
On 02/13/2014 06:46 AM, Antony Lee wrote:
> Even more generally (not sure allowing multiple clauses is a good idea but
> at least "if" sounds better than "for", I think.

Agreed.

foo = something() except None if BarException

d

spir

unread,
Feb 13, 2014, 5:45:00 AM2/13/14
to python...@python.org
On 02/13/2014 06:53 AM, Amber Yust wrote:
> The reason why I suggested 'for' is that it still flows somewhat naturally
> - it's using "for" in the sense of "associated with" or "in the place of".
> "I'll give you my None for your FooException."

True, but it is probably not wise to use a natural language preposition in two
different syntactic schemas with two different meanings: here 'for' meaning
either traversal loop or "expression-exception-condition" (would be ok if the
meaning was the same).

d

spir

unread,
Feb 13, 2014, 6:02:03 AM2/13/14
to python...@python.org
On 02/13/2014 10:24 AM, 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).

I think the right way is not to call the function at all, but to check it.
Conceptually:

if col.is_empty():
handle_special_case()
else:
handle_standard_case()

> One use case, for example, is handing IndexError when retrieving an item
> from a sequence (which currently has no nice standard spelling, and isn't
> amenable to the "pass in a default answer" solution because it isn't a
> normal function call).
>
> Another case not handled well by the status quo is when the default answer
> is expensive to calculate for some reason, so you really only want to
> calculate it if you actually need it.

The above schema applies to all cases where the failure (for the called service
to perform its task) is _predictable_ by the client. Exceptions, in my view, are
only for cases where the failure is impredictable (see below) *and* nevertheless
belongs to to the application semantics; meaning, it does not result from a
programming error (eg the collection should _not_ be empty), else one should not
use exception catching, but instead let an error message helpfully inform us
about the logical error.

Typical cases of impredictability on the client side are search/find functions,
and dealing with the outer world, in particular the file system. In addition, in
such cases using for instance a 'has' function (or in python 'in') to first
check would do the job (of searching) twice. This is why, probably, there are
alternative funcs like python's 'get' for dicts. Maybe this scheme could be
generalised: not only eg list.get(i, default), but all cases of potentially
failing funcs that return a result.

For functions (actions, in fact) that instead perform an effect, cases are more
diverse and not always in our hands. For instance, one may think at a func which
would create file if not existant, instead of replacing its contents (or
appending to it): but this would I guess require the filesystem to provide such
a facility. As far as I know, we are left with having routines search twice (for
the abstract file location in the dir tree).

d

Ben Finney

unread,
Feb 13, 2014, 6:10:16 AM2/13/14
to python...@python.org
spir <denis...@gmail.com> writes:

> I think the right way is not to call the function at all, but to check
> it. Conceptually:
>
> if col.is_empty():
> handle_special_case()
> else:
> handle_standard_case()

Or, better from two perspectives (“empty” should normally entail
“evaluates to boolean false”; and, the normal case should be the first
branch from the “if”)::

if col:
handle_standard_case()
else:
handle_empty_case()

--
\ “Intellectual property is to the 21st century what the slave |
`\ trade was to the 16th.” —David Mertz |
_o__) |
Ben Finney

Ram Rachum

unread,
Feb 13, 2014, 6:14:13 AM2/13/14
to python...@googlegroups.com


Sent from my phone.


On Feb 13, 2014 1:11 PM, "Ben Finney" <ben+p...@benfinney.id.au> wrote:
>
> spir <denis...@gmail.com> writes:
>
> > I think the right way is not to call the function at all, but to check
> > it. Conceptually:
> >
> >   if col.is_empty():
> >       handle_special_case()
> >   else:
> >       handle_standard_case()
>
> Or, better from two perspectives (“empty” should normally entail
> “evaluates to boolean false”; and, the normal case should be the first
> branch from the “if”)::
>
>     if col:
>         handle_standard_case()
>     else:
>         handle_empty_case()

This, like Spir's snippet, is not an atomic action, which can be a problem when using threads. (The queue says it's not empty but by the time you ask for an item it's empty.)


>
> --
>  \        “Intellectual property is to the 21st century what the slave |
>   `\                              trade was to the 16th.” —David Mertz |
> _o__)                                                                  |
> Ben Finney
>
> _______________________________________________
> Python-ideas mailing list
> Python...@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>

> --
>
> ---
> You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/python-ideas/ZoBGdwuH3uk/unsubscribe.

> To unsubscribe from this group and all its topics, send an email to python-ideas...@googlegroups.com.

spir

unread,
Feb 13, 2014, 6:25:07 AM2/13/14
to python...@python.org
On 02/13/2014 04:38 AM, Chris Angelico wrote:
> On Thu, Feb 13, 2014 at 2:20 PM, Amber Yust <amber...@gmail.com> wrote:
>> Ah, that's a good point (the two-directionality of yield had slipped my
>> mind). I had considered suggesting return instead of yield, which wouldn't
>> have that problem, but it felt like return would be more confusing to see in
>> a context where it doesn't actually return from the enclosing scope.
>
> Yeah. I like the parallel with "get this unless it's empty in which
> case use this default", but the 'or' keyword is already a bit awkward
> there, so I don't want to advocate that.
>
> name = input("Name [Anonymous]: ") or "Anonymous"
> phone = addressbook[name] except KeyError or "Unknown"
>
> It's a nice parallel, but doesn't read well (plus, >> KeyError or
> "Unknown" << is already an expression).
>
> +1 on the feature but it definitely needs a syntax that makes sense.

I don't see any issue with:
phone = addressbook[name] except "Unknown" if KeyError
phone = addressbook[name] except "Unknown" if KeyError as e
It is similar in syntax and meaning with if-expressions, with the first keyword
'except' obviously making all the difference we need.

[By the way, this shows that:
x = b if cond else a
should really be:
x = a else b if cond
The difference being that the standard case is expressed first, the exceptional
one being then introduced as an special variant.]

In some languages (eg Lua) there is no difference between absent values (vars,
attributes, items...) because of an arror (they should be there, in python we
get an exception) and optional values (in python there is None for this
meaning). In the latter case, presence of absence both are valid alternatives in
the app's logic. Such a lack of distinction (in Lua, both yield nil) is very
bad, indeed, but combined with "permissive" logical expressions (in which
operands may not be logical, and result value as well) allows:
phone = addressbook[name] or "Unknown"

However, this idiom is mainly common in lua because there are no standard param
values (defaults):
Shape.fill = function (shape, color)
color = color or black
...
end
This also shows that the cases in python were we do need such an idiom are
pretty rare, all in all: should we bother?

> Of course, it could be done as a function call:
>
> def catch(callme, catchme, returnme):
> try:
> return callme()
> except catchme:
> return returnme
>
> phone = catch(lambda: addressbook[name], KeyError, "Unknown")
>
> but that's *really* clunky.

I'd like such a solution if builtin (for it to be standard, thus widely shared
in python code) and did not force writing a lambda.

d

spir

unread,
Feb 13, 2014, 6:27:13 AM2/13/14
to python...@python.org
On 02/13/2014 12:10 PM, Ben Finney wrote:
> spir <denis...@gmail.com> writes:
>
>> I think the right way is not to call the function at all, but to check
>> it. Conceptually:
>>
>> if col.is_empty():
>> handle_special_case()
>> else:
>> handle_standard_case()
>
> Or, better from two perspectives (“empty” should normally entail
> “evaluates to boolean false”; and, the normal case should be the first
> branch from the “if”)::
>
> if col:
> handle_standard_case()
> else:
> handle_empty_case()

You are right (I always forget that empty means false in python, in a logical
context, which i don't find obvious at all --I wonder if any other lang follows
this choice).

d

Paul Moore

unread,
Feb 13, 2014, 6:36:55 AM2/13/14
to spir, Python-Ideas
On 13 February 2014 11:25, spir <denis...@gmail.com> wrote:
> I don't see any issue with:
> phone = addressbook[name] except "Unknown" if KeyError
> phone = addressbook[name] except "Unknown" if KeyError as e
> It is similar in syntax and meaning with if-expressions, with the first
> keyword 'except' obviously making all the difference we need.

What I dislike about this variant is that in a normal try statement,
the exception goes after the "except" keyword. Here, it's the
alternative value that goes there. I find that very easy to misread.

Personally, I quite like "EXPR except EXCEPTIONTYPE return VALUE" if
we have to stick with existing keywords. If I had free rein I might go
for a new keyword "then" instead of "return".

Paul

Chris Angelico

unread,
Feb 13, 2014, 6:48:08 AM2/13/14
to python-ideas
On Thu, Feb 13, 2014 at 10:25 PM, spir <denis...@gmail.com> wrote:
> I don't see any issue with:
> phone = addressbook[name] except "Unknown" if KeyError
> phone = addressbook[name] except "Unknown" if KeyError as e
> It is similar in syntax and meaning with if-expressions, with the first
> keyword 'except' obviously making all the difference we need.

So the keyword 'if' would come up in two different expression contexts:

value if cond else othervalue

value except othervalue if cond

In each case, the condition (which in the latter is an exception type,
while in the former it's a boolean) follows the word 'if', just as it
does in the statement form. That's reasonably elegant. Problem is,
that loses the elegance of matching the statement form of 'except',
which has the exception type following the word 'except'.

I'd kinda like to see it worded as "if except", but then it needs
something else to separate the exception(s) from the value. It could
actually be done just like the if/else form, except (pun intended)
that that overemphasizes the exceptional case:

phone = "Unknown" if except KeyError else addressbook[name]

In terms of argument order, I'm looking for:

phone = addressbook[name] unless except KeyError as e then "Unknown"

but neither 'unless' nor 'then' is currently a keyword.

> [By the way, this shows that:
> x = b if cond else a
> should really be:
> x = a else b if cond
> The difference being that the standard case is expressed first, the
> exceptional one being then introduced as an special variant.]

My example tends to agree with you... but my example is using "if" to
introduce the abnormal case, whereas it's common to spell a block if
the other way:

if normal-case:
code code code
else:
abnormal code

C's ternary operator puts the expressions in the order "condition,
if_true, if_false". Python's puts them "if_true, condition, if_false".
You're proposing "if_false, if_true, condition". We're half way to
covering all the permutations!

ChrisA

Chris Angelico

unread,
Feb 13, 2014, 6:50:36 AM2/13/14
to Python-Ideas
On Thu, Feb 13, 2014 at 10:36 PM, Paul Moore <p.f....@gmail.com> wrote:
> Personally, I quite like "EXPR except EXCEPTIONTYPE return VALUE" if
> we have to stick with existing keywords. If I had free rein I might go
> for a new keyword "then" instead of "return".

Hmm. Stupid idea:

EXPR expr EXCEPTIONTYPE pass VALUE

Passing something is kinda like returning it, right? *ducks the rotten tomatoes*

ChrisA

Ram Rachum

unread,
Feb 13, 2014, 6:54:04 AM2/13/14
to python...@googlegroups.com, Python-Ideas
On Thu, Feb 13, 2014 at 1:50 PM, Chris Angelico <ros...@gmail.com> wrote:
On Thu, Feb 13, 2014 at 10:36 PM, Paul Moore <p.f....@gmail.com> wrote:
> Personally, I quite like "EXPR except EXCEPTIONTYPE return VALUE" if
> we have to stick with existing keywords. If I had free rein I might go
> for a new keyword "then" instead of "return".

Hmm. Stupid idea:

EXPR expr EXCEPTIONTYPE pass VALUE

Passing something is kinda like returning it, right? *ducks the rotten tomatoes*

_______________________________________________
Python-ideas mailing list
Python...@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

spir

unread,
Feb 13, 2014, 6:53:28 AM2/13/14
to Paul Moore, Python-Ideas
On 02/13/2014 12:36 PM, Paul Moore wrote:
> On 13 February 2014 11:25, spir<denis...@gmail.com> wrote:
>> >I don't see any issue with:
>> > phone = addressbook[name] except "Unknown" if KeyError
>> > phone = addressbook[name] except "Unknown" if KeyError as e
>> >It is similar in syntax and meaning with if-expressions, with the first
>> >keyword 'except' obviously making all the difference we need.
> What I dislike about this variant is that in a normal try statement,
> the exception goes after the "except" keyword. Here, it's the
> alternative value that goes there. I find that very easy to misread.

You are right!

d

Chris Angelico

unread,
Feb 13, 2014, 7:00:02 AM2/13/14
to python-ideas
On Thu, Feb 13, 2014 at 10:54 PM, Ram Rachum <r...@rachum.com> wrote:
> On Thu, Feb 13, 2014 at 1:50 PM, Chris Angelico <ros...@gmail.com> wrote:
>>
>> On Thu, Feb 13, 2014 at 10:36 PM, Paul Moore <p.f....@gmail.com> wrote:
>> > Personally, I quite like "EXPR except EXCEPTIONTYPE return VALUE" if
>> > we have to stick with existing keywords. If I had free rein I might go
>> > for a new keyword "then" instead of "return".
>>
>> Hmm. Stupid idea:
>>
>> EXPR expr EXCEPTIONTYPE pass VALUE
>>
>> Passing something is kinda like returning it, right? *ducks the rotten
>> tomatoes*
>
> http://i.imgur.com/xk003.gif

Do you mean my idea is win, or the notion of throwing rotten tomatoes
at me is win? I'm inclined to the latter theory :)

Oh, and that should be "EXPR except EXCEPTIONTYPE", of course. I
wasn't sure if I'd clicked Send or not, edited, and reclicked Send, so
you may have a corrected copy as well as that one. But you knew
already what it ought to have been.

spir

unread,
Feb 13, 2014, 7:07:51 AM2/13/14
to python...@python.org
On 02/13/2014 12:48 PM, Chris Angelico wrote:
On Thu, Feb 13, 2014 at 10:25 PM, spir <denis...@gmail.com> wrote:
> > [By the way, this shows that:
> > x = b if cond else a
> > should really be:
> > x = a else b if cond
> > The difference being that the standard case is expressed first, the
> > exceptional one being then introduced as an special variant.]
>
> My example tends to agree with you... but my example is using "if" to
> introduce the abnormal case, whereas it's common to spell a block if
> the other way:
>
> if normal-case:
> code code code
> else:
> abnormal code

I rather write code the the other way round, with the condition determinig the
special case. This also matches the common idom:
if special-case:
deal-with-it
return [result]
deal-with-normal-case # no else needed

Generally, I think logical vars should be 'false' by default, expressing the
standard/rest/off state, with 'true' meaning something new or activated ('on'),
or otherwise special.

> C's ternary operator puts the expressions in the order "condition,
> if_true, if_false". Python's puts them "if_true, condition, if_false".
> You're proposing "if_false, if_true, condition".

That's because I think (1) the standard value should come first (2) the
condition should express the special case instead.

> We're half way to
> covering all the permutations!

;-)

Actually, the ideal order for me would be:
if_false, condition, if_true
in the sense of
normal_value, special_condition, special_value
but this does not match the meaning of natural language preposition (here, 'if').

d

spir

unread,
Feb 13, 2014, 7:11:23 AM2/13/14
to python...@python.org
On 02/13/2014 01:00 PM, Chris Angelico wrote:
> On Thu, Feb 13, 2014 at 10:54 PM, Ram Rachum <r...@rachum.com> wrote:
>> On Thu, Feb 13, 2014 at 1:50 PM, Chris Angelico <ros...@gmail.com> wrote:
>>>
>>> On Thu, Feb 13, 2014 at 10:36 PM, Paul Moore <p.f....@gmail.com> wrote:
>>>> Personally, I quite like "EXPR except EXCEPTIONTYPE return VALUE" if
>>>> we have to stick with existing keywords. If I had free rein I might go
>>>> for a new keyword "then" instead of "return".
>>>
>>> Hmm. Stupid idea:
>>>
>>> EXPR expr EXCEPTIONTYPE pass VALUE
>>>
>>> Passing something is kinda like returning it, right? *ducks the rotten
>>> tomatoes*
>>
>> http://i.imgur.com/xk003.gif
>
> Do you mean my idea is win, or the notion of throwing rotten tomatoes
> at me is win? I'm inclined to the latter theory :)
>
> Oh, and that should be "EXPR except EXCEPTIONTYPE", of course. I
> wasn't sure if I'd clicked Send or not, edited, and reclicked Send, so
> you may have a corrected copy as well as that one. But you knew
> already what it ought to have been.

Your proposal has the big advantage of stating things in (the right) order:
normal_value, special_condition, special_value
and it still lets the door open to naming the exception, using 'as', if later
needed:
EXPR except EXCEPTIONTYPE as EXCEPTIONNAME pass VALUE

d

Nick Coghlan

unread,
Feb 13, 2014, 7:50:55 AM2/13/14
to M.-A. Lemburg, python...@python.org
On 13 February 2014 20:10, M.-A. Lemburg <m...@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.

--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia

Philipp A.

unread,
Feb 13, 2014, 8:19:10 AM2/13/14
to Nick Coghlan, python...@python.org, M.-A. Lemburg
actually i like the first proposal, because it mirrors “the trinary”:

```python
'spam' if mustard else 'eggs'
eat() except SickException else puke()
```

but it’s a bit weird.

I don’t like `return` at all, because it’s exclusively about returning from functions. `for` is for loops. And qhile from is used more versatile, it’s even weirder than `else` here.

I also don’t like putting anythiing but the exception type after the `except`.

It should definitely be `EXPR except EXC_TYPE [as EXC_NAME] KEYWORD ALT_EXPR`, with `EXC_NAME` being defined in `ALT_EXPR` and afterwards.

and i’m leaning towards `pass` or `else` as `KEYWORD`. `pass` is only used to mean “do nothing” right now, and indeed that’s fitting: it’s just a border between `EXC_TYPE [as EXC_NAME]` and `ALT_EXPR`, and its other meaning makes sense in english grammar. Maybe even `try`? Like “use this, except if that doesn’t work, then try using the other thing”.

Ram Rachum

unread,
Feb 13, 2014, 8:26:01 AM2/13/14
to python...@googlegroups.com, python...@python.org, M.-A. Lemburg
My favorite syntax so far is: 

    x except Exception pass y

    x except Exception as e pass e.y

As weird as it is to use pass this way, it's better than using return. It's better than not having the exception immediately follow `except`, it's better than using a colon, it's better than all the other possible compromises we could make.


Rob Cliffe

unread,
Feb 13, 2014, 8:26:57 AM2/13/14
to python...@python.org
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

Terry Reedy

unread,
Feb 13, 2014, 8:38:32 AM2/13/14
to python...@python.org
On 2/13/2014 5:10 AM, M.-A. Lemburg 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

In Python 3 that would be
x = something() except ValueError as exc return exc.args[0]

> 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

x = something() except ValueError as exc try exc.message

Try otherthing instead of something. That could even be chained

x = something() except ValueError as exc continue with exc.message

Instead of breaking due to the exception; 'with' could be left out.

x = something() except ValueError as exc pass exc.message

Pass expression back to x or consumer of expression.

--
Terry Jan Reedy

Paul Moore

unread,
Feb 13, 2014, 9:34:29 AM2/13/14
to ru...@yahoo.com, Python-Ideas
But because the GG gateway isn't transparent I have to manually edit
the headers when I reply-all and if I don't I get a rejection message.
Never mind, I appreciate that you find it convenient, I was just
pointing out that it inconveniences others (as has been pointed out a
few times in the past on this list)

Paul

On 13 February 2014 02:49, ru...@yahoo.com <ru...@yahoo.com> wrote:
> On Wednesday, February 12, 2014 3:00:20 PM UTC-7, Paul Moore wrote:
>>
>> On 12 February 2014 21:02, Ram Rachum <ram.r...@gmail.com> wrote:
>> [...]
>>
>> PS Looks like posting via google groups not only breaks filtering and
>> threading, it also breaks reply-all (as I can't post to the google
>> group). Could you please post direct to the group rather than through
>> the google groups interface? Thanks.
>
>
> There is no need for you to explicitly reply to Google Groups -- it is
> gatewayed to the ideas list. Here is a link to your post on GG:
> https://groups.google.com/d/msg/python-ideas/ZoBGdwuH3uk/49PE5ufVHYAJ
> Many people find GG convenient and prefer to use it.

Georg Brandl

unread,
Feb 13, 2014, 9:53:48 AM2/13/14
to python...@python.org
Am 13.02.2014 12:25, schrieb spir:

> [By the way, this shows that:
> x = b if cond else a
> should really be:
> x = a else b if cond
> The difference being that the standard case is expressed first, the exceptional
> one being then introduced as an special variant.]

No it shouldn't -- your syntax associates "b" with both the else ("else b") and
the "if" clause ("b if cond"), which makes me think "which of them will it be".

Also, there's nothing intrinsically more "exceptional" about the "if" branch
than the "else" branch; this entirely dependent on the expression.

Georg

Georg Brandl

unread,
Feb 13, 2014, 9:58:06 AM2/13/14
to python...@python.org
For me any proposal that doesn't pair "except" with the exception class(es)
like the statement version does would be right out.

It will be hard enough to remember the order of the expression, but "in
the try-except block except gets the exception class, in the except
expression it gets the default value and the exception class is specified
with FOO" is silly.

Georg

Terry Reedy

unread,
Feb 13, 2014, 10:28:05 AM2/13/14
to python...@python.org
On 2/13/2014 4:24 AM, 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).

Leaving aside syntax, the idea makes sense to me as follows:

In Python, 'a or b' is not a just a logic operator but is generalized to
mean, for instance, the following: 'a, unless a is falsey, in which
case, b instead. The proposal is to introduce a syntax that means the
same with 'unless a is falsey' replaced by 'unless a raises an exception
of class C'. The class 'C' make 'a new_op b' inadequate.

The two alternations are related when exception C results from an input
that is at least conceptually falsey. Some such cases can be handled by
'or' (see below). Iterators, however, are seen as truthy even when empty
(conceptually falsey). And that cannot be fixed since some iterators
cannot know if they are empty until __next__ is called and bool is not
supposed to raise.

> One use case, for example, is handing IndexError when retrieving an item
> from a sequence (which currently has no nice standard spelling, and
> isn't amenable to the "pass in a default answer" solution because it
> isn't a normal function call).

This is easy, if not obvious

>>> (seq or ['default'])[0]
'default'

(Python's precedence rules make the parentheses optional).

Doing something similar instead of dict.get is messier but conceptually
the same.

>>> {}.get('key', 'default')
'default'
>>> {} or {'key':'default'}['key']
'default'

The general scheme is f(a or b, *args), where b is the input to f that
gives the default as the output. Sort of inverse(partial(f, args))(default).

This does not work if the exception-raising inputs are not all seen as
falsey (as with empty iterables) or if one cannot invert the partial
function to get b. In either case, we have to input a and replace
exceptions with b.

--
Terry Jan Reedy

Georg Brandl

unread,
Feb 13, 2014, 10:36:43 AM2/13/14
to python...@python.org
Not sure if I understand correctly, but in the example above they are not.

> Doing something similar instead of dict.get is messier but conceptually
> the same.
>
> >>> {}.get('key', 'default')
> 'default'
> >>> {} or {'key':'default'}['key']
> 'default'

And this also quite certainly does not do what you intended.

Georg

Terry Reedy

unread,
Feb 13, 2014, 11:18:37 AM2/13/14
to python...@python.org
On 2/13/2014 10:28 AM, Terry Reedy wrote:
> On 2/13/2014 4:24 AM, 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).
>
> Leaving aside syntax, the idea makes sense to me as follows:
>
> In Python, 'a or b' is not a just a logic operator but is generalized to
> mean, for instance, the following: 'a, unless a is falsey, in which
> case, b instead. The proposal is to introduce a syntax that means the
> same with 'unless a is falsey' replaced by 'unless a raises an exception
> of class C'. The class 'C' make 'a new_op b' inadequate.
>
> The two alternations are related when exception C results from an input
> that is at least conceptually falsey. Some such cases can be handled by
> 'or' (see below). Iterators, however, are seen as truthy even when empty
> (conceptually falsey). And that cannot be fixed since some iterators
> cannot know if they are empty until __next__ is called and bool is not
> supposed to raise.
>
>> One use case, for example, is handing IndexError when retrieving an item
>> from a sequence (which currently has no nice standard spelling, and
>> isn't amenable to the "pass in a default answer" solution because it
>> isn't a normal function call).
>
> This is easy, if not obvious

To be fair, this is only easy for the index 0 case, which is however,
common.

> >>> (seq or ['default'])[0]
> 'default'
>
> (Python's precedence rules make the parentheses optional).
>
> Doing something similar instead of dict.get is messier but conceptually
> the same.

> >>> {}.get('key', 'default')
> 'default'
> >>> {} or {'key':'default'}['key']
> 'default'

However, this is a rare case.

> The general scheme is f(a or b, *args), where b is the input to f that
> gives the default as the output. Sort of inverse(partial(f,
> args))(default).
>
> This does not work if the exception-raising inputs are not all seen as
> falsey (as with empty iterables)

or with non-empty lists whose length is less than the index+1
(though this latter example can be 'fixed' by using a conditional
expression).

> or if one cannot invert the partial function to get b.

Or if it is unboundedly expensive.

>>> (lis if len(lis) > n else (n+1)*['default'])[n] # () needed
'default'

Doing something similar for a non-empty dict that might be missing a key
is at least as messy.

>In either case, we should or must input a and replace exceptions with b.

MRAB

unread,
Feb 13, 2014, 11:38:36 AM2/13/14
to python...@python.org
You left one out:

x = op() except Exception: default

spir

unread,
Feb 13, 2014, 1:30:08 PM2/13/14
to python...@python.org
On 02/12/2014 10:02 PM, Ram Rachum wrote:
> Hi,
>
> Here's an idea that would help shortening code. Allow a ternary expression
> based on except, like so:
>
> first_entry = entries[0] except IndexError else None
> item = my_queue.get() except queue.Empty else None
> response_text = request('http://whatever.com').text except HttpError
> else "Can't access data"
>
> Aside from the fact that this would be a big grammar addition, a big
> problem here is the usage of the `else` keyword, that when used with except
> usually means "what would happen if there wasn't an exception" and here
> means the opposite. But I couldn't think of a nicer syntax.
>
> I realize that this is a big change and that most people would be opposed
> to this... But I guess I just wanted to share my idea :)

After some considerations, it seems we reached the point of generalising the
idea to:
* provide a builtin way to indicate a special value for the special cases where
the standard value's expression would raise an exception
As Nick Coghlan shows in another post, this is in fact close to a builtin way to
deal with potentially failing functions, in general (below 'op'):

def _helper(op, exc, make_default):
try:
return op()
except exc:
return make_default()

x = _helper(op, Exception, make_default)

However, this only applies to the case of functions properly speaking (which
purpose is computing a product). What about 'actions', meaning procedures that
perform an effect? Take the case of count-words for instance, where (in python)
when encoutering a word one would add 1 to its count in a dict which keys are
the words. On first encounter, there no entry yet for that word. We could check
"word in word_counts", but this is doing the dict lookup twice; and catching an
exception is worse.

The problem I guess, here and also similarly for functions, is that there is no
way for the _client_ (the caller) to control exception throwing; while only the
caller knows whether the failing case actually is an error or not, meaning
belongs or not the application's logics. Maybe what we need is in fact something
like:

maybe statement
[then
dependant-block]
else
alternative-block

This is similar in form to exception catching except (sic!) that the actual
meaning is to _avoid_ an exception, not to catch it (to avoid it beeing thrown
at all). More or less the opposite, in fact. The consequence is that in case of
failure no exception is raised, instead the alternative 'else' branch is taken.
Such a construct would work fine for both called actions and functions (which
calls are expressions in statement). [1]

[Similar considerations are evoked in other languages, especially D where I
first met them. Generally speaking, people start to realise the seamntic
weakness of typical exception catching mecanisms which let no choice or control
in the hands of the one who actually knows, namely the client.]

d

[1] Practically, this just means adding a test before throwing, and setting a
flag instead (the carry would do the job nicely, since it can have no meaning on
func return, and is the only copy flag one can set arbitrarily).

Thus, the above code translates to:
statement
if flag:
reset flag
alternative-block
[else:
dependant-block]

David Mertz

unread,
Feb 13, 2014, 1:31:28 PM2/13/14
to spir, python-ideas
On Thu, Feb 13, 2014 at 3:25 AM, spir <denis...@gmail.com> wrote:
Of course, it could be done as a function call:

def catch(callme, catchme, returnme):
   try:
     return callme()
   except catchme:
     return returnme

phone = catch(lambda: addressbook[name], KeyError, "Unknown")
but that's *really* clunky.

I don't really find this function all the clunky.  However, it also does not solve the case of an expensive 'except' clause that Nick pointed out as desirable to avoid evaluating (or, for that matter, an except clause with side effects).

E.g.

  phone = catch(lambda: addressbook[name], KeyError, lookup_from_internet(name))




--
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is

Amber Yust

unread,
Feb 13, 2014, 1:43:59 PM2/13/14
to David Mertz, spir, python-ideas
Actually. What if we just reused 'try'?

    foo = bar() except BazException try 'qux'

This also leads naturally to chaining multiple possible fallbacks:

    foo = bar() except BarException try baz() except BazException try None

spir

unread,
Feb 13, 2014, 1:45:18 PM2/13/14
to python...@python.org
On 02/13/2014 02:26 PM, Rob Cliffe wrote:
> 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

What about:
x = entries[0] except IndexError then None

The weird point with:
x = entries[0] except IndexError else None

is that 'else' seems to introduce a kind of double negation, where the first
negation is due to 'except'. It this seems to indicate what _not_ to do in case
of exception, which indeed makes no sense. 'else instead is ok in reverse order:
x = entries[0] else None if IndexError

However, 'then' in python normally introduces an action, meaning a statement or
block (and I'm firmly opposed to giving unrelated meanings to keywords or
signs). But in such a case, an expression context, the action is just to choose
and pick a value (here for the assignment), thus finally I don't find it that bad.

d

spir

unread,
Feb 13, 2014, 1:47:05 PM2/13/14
to Amber Yust, David Mertz, python-ideas
On 02/13/2014 07:43 PM, Amber Yust wrote:
> Actually. What if we just reused 'try'?
>
> foo = bar() except BazException try 'qux'
>
> This also leads naturally to chaining multiple possible fallbacks:
>
> foo = bar() except BarException try baz() except BazException try None

I like it. Especially because 'try' already works with 'except'. (But note that
'try', like my proposal of 'then', normally introduces a block).

d

Philipp A.

unread,
Feb 13, 2014, 1:54:37 PM2/13/14
to spir, python-ideas
mainly, a colon introduces a block, which is why i don’t like the colon variant of this expression.

Nathan Schneider

unread,
Feb 13, 2014, 2:04:59 PM2/13/14
to spir, python-ideas
On Thu, Feb 13, 2014 at 1:47 PM, spir <denis...@gmail.com> wrote:
On 02/13/2014 07:43 PM, Amber Yust wrote:
Actually. What if we just reused 'try'?

     foo = bar() except BazException try 'qux'

This also leads naturally to chaining multiple possible fallbacks:

     foo = bar() except BarException try baz() except BazException try None

I like it. Especially because 'try' already works with 'except'. (But note that 'try', like my proposal of 'then', normally introduces a block).


This strikes me as counterintuitive because it is inconsistent: 'bar()' is being tried, but does not follow 'try', while the others do. And then the 'try None' has no corresponding 'except'.

Suggestion: an expression like

    foo = (try bar() except BarException)

that defaults to None if the exception is caught. This could then be chained with 'or':

    foo = (try bar() except BarException) or (try baz() except BazException)

as distinguished from

    foo = (try bar() except BarException) or baz()

which does not do any exception handling for baz().

(Apologies if something like this has been proposed above; I could not find it from skimming the thread.)

Nathan

Andrew Barnert

unread,
Feb 13, 2014, 2:17:45 PM2/13/14
to Nathan Schneider, python-ideas
On Feb 13, 2014, at 11:04, Nathan Schneider <nat...@cmu.edu> wrote:

On Thu, Feb 13, 2014 at 1:47 PM, spir <denis...@gmail.com> wrote:
On 02/13/2014 07:43 PM, Amber Yust wrote:
Actually. What if we just reused 'try'?

     foo = bar() except BazException try 'qux'

This also leads naturally to chaining multiple possible fallbacks:

     foo = bar() except BarException try baz() except BazException try None

I like it. Especially because 'try' already works with 'except'. (But note that 'try', like my proposal of 'then', normally introduces a block).


This strikes me as counterintuitive because it is inconsistent: 'bar()' is being tried, but does not follow 'try', while the others do. And then the 'try None' has no corresponding 'except'.

Suggestion: an expression like

    foo = (try bar() except BarException)

that defaults to None if the exception is caught. This could then be chained with 'or':

    foo = (try bar() except BarException) or (try baz() except BazException)

But what if bar() can successfully return None, or just a falsey value in general?

Note that this is exactly the reason we needed the if expression: because or is tempting but incorrect in such cases.

Andrew Barnert

unread,
Feb 13, 2014, 2:19:27 PM2/13/14
to spir, python...@python.org
On Feb 13, 2014, at 10:45, spir <denis...@gmail.com> wrote:

> On 02/13/2014 02:26 PM, Rob Cliffe wrote:
>> 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
>
> What about:
> x = entries[0] except IndexError then None
>
> The weird point with:
> x = entries[0] except IndexError else None
>
> is that 'else' seems to introduce a kind of double negation, where the first negation is due to 'except'. It this seems to indicate what _not_ to do in case of exception, which indeed makes no sense. 'else instead is ok in reverse order:
> x = entries[0] else None if IndexError
>
> However, 'then' in python normally introduces an action,

'then' in Python normally means nothing.

If Python _had_ a then keyword in it's if statement, there would have been a much more obvious syntax for the if expression, but it doesn't.