except expression

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

Andrew Barnert

unread,
Feb 13, 2014, 2:39:05 PM2/13/14
to spir, python...@python.org
Or you could use setdefault, or use a defaultdict, or, better, a Counter.

And I don't see how you expect to handle this situation with new syntax. You want to do word_counts[word] = 0 in the case where word_counts[word] raised--but you also want to "unfail" that word_counts[word] and provide a value for it to return. That can't be the value of word_counts[word] = 0, because statements don't have values. And, even if you could figure out how to provide the number 0, that wouldn't help anyway, because what you're looking for is an augmented assignment target, and those aren't even values in the language that can be passed around.

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

How do you avoid an exception being thrown? What happens if some function called inside statement tries to raise?

If the answer is "we immediately abort that function, and the rest of the statement, and run the alternative block, then what you've described is just exception handling, as it already exists:

try:
statement
except:
alternative block
else:
dependent block

All you've done is make it less powerful--you can't limit it to specific types, use the value of the exception, try a complex statement, etc.

And I can't think of any other sensible think you could mean here.

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

Are you just looking to use a flag to shortcut the creation and propagation of an exception object here? If not, in what other way is this semantically different from "an exception is raised, and handled by the alternative branch"?

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

And then continuing to execute the rest of the function? Or constructing and returning some value nobody will ever look at?

And what happens if the exception is raised in a function three levels down the stack? How are you going to abort all three of them?

Really, the only thing you can do when the function tries to raise is to abort the whole function, and all the way up to some piece of code that's looking to deal with the problem. You need a flag that's checked in multiple places in the interpreter to make sure it's propagated correctly.

Which is exactly what raise already does. So you'd just be providing a different kind of exception--one that can't be caught by try/except, but can be caught by maybe. But if you want two kinds of exception, why not many kinds, which any hierarchy you want--which you can already do today, because exception types are classes.

Greg Ewing

unread,
Feb 13, 2014, 4:18:01 PM2/13/14
to python-ideas
Chris Angelico wrote:

> phone = addressbook[name] except KeyError or "Unknown"

How about

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

Yes, it puts things in a different order from the except
statement, but I don't think that's any worse than the
if-expression being ordered differently from the if-statement,
and it has the same benefit, i.e. reading more smoothly.

--
Greg

Amber Yust

unread,
Feb 13, 2014, 4:26:42 PM2/13/14
to Greg Ewing, python-ideas
As has been noted earlier in the thread when someone proposed except...if - there are parsing issues due to if..else already being a ternary expression.

Greg Ewing

unread,
Feb 13, 2014, 4:31:48 PM2/13/14
to python...@python.org
Nick Coghlan wrote:
> "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).

I don't think that would be an insurmountable difficulty.
The if-expression appears at the 'test' level in the grammar,
so all it should take is for the expression following
'except' to be something lower, such as an 'or_test'.

There are precedents for this kind of thing, e.g. yield
expressions can appear unparenthesised in some contexts
but not others.

Steven D'Aprano

unread,
Feb 13, 2014, 4:38:37 PM2/13/14
to python...@python.org
On Thu, Feb 13, 2014 at 10:10:16PM +1100, 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()

I'm afraid that entails a race-condition. col may be non-empty at the
moment you check it, but by the time you handle the non-empty case a
microsecond later it has become empty.

This is why we have both Look Before You Leap and Easier To Ask
Forgiveness Than Permission. We can perform LBYL in an expression using
ternary if operator:

(handle_standard_case if col else handle_empty_case)()

but there's no equivalent to a try...except in a single
expression, which is what this thread is about.


--
Steven

Zachary Ware

unread,
Feb 13, 2014, 4:55:56 PM2/13/14
to python-ideas
On Thu, Feb 13, 2014 at 12:43 PM, Amber Yust <amber...@gmail.com> 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

This is my favorite so far, followed by s/try/return/. I agree with
Nathan Schneider though, it does seem odd to have "try" following
"except" rather than the other way around.

What about just allowing simple try...except constructs to be
condensed to a single line?

foo = try bar() except BarException as e e.args[0]

--
Zach

Amber Yust

unread,
Feb 13, 2014, 5:02:23 PM2/13/14
to Zachary Ware, python-ideas
The last part of that ("as e e.args[0]") is a pain to read due to no clear separation, just whitespace.

Zachary Ware

unread,
Feb 13, 2014, 5:11:15 PM2/13/14
to python-ideas
On Thu, Feb 13, 2014 at 4:02 PM, Amber Yust <amber...@gmail.com> wrote:
<cut>
> On Thu Feb 13 2014 at 2:00:00 PM, Zachary Ware
> <zachary.wa...@gmail.com> wrote:
>> What about just allowing simple try...except constructs to be
>> condensed to a single line?
>>
>> foo = try bar() except BarException as e e.args[0]
<paste>
> The last part of that ("as e e.args[0]") is a pain to read due to no clear
> separation, just whitespace.

I don't disagree, but it's less bad than some of the other
alternatives :). It's also not quite as bad when not using the
exception (which I suspect would be somewhat more common):

foo = try bar() except BarException "default"

--
Zach

PS: I know Gmail makes it harder than it needs to be, but could you
please try to avoid top-posting? (This topic doesn't need to be
derailed into another debate about top-posting though, so please
either follow this suggestion or ignore it entirely :))

Greg Ewing

unread,
Feb 13, 2014, 5:22:05 PM2/13/14
to python-ideas
Chris Angelico wrote:
> phone = "Unknown" if except KeyError else addressbook[name]

-42. My brain gets totally derailed when it hits "if except";
it parses that bit as a syntax error.

--
Greg

Chris Angelico

unread,
Feb 13, 2014, 5:23:06 PM2/13/14
to python-ideas
On Fri, Feb 14, 2014 at 9:11 AM, Zachary Ware
<zachary.wa...@gmail.com> wrote:
> On Thu, Feb 13, 2014 at 4:02 PM, Amber Yust <amber...@gmail.com> wrote:
> <cut>
>> On Thu Feb 13 2014 at 2:00:00 PM, Zachary Ware
>> <zachary.wa...@gmail.com> wrote:
>>> What about just allowing simple try...except constructs to be
>>> condensed to a single line?
>>>
>>> foo = try bar() except BarException as e e.args[0]
> <paste>
>> The last part of that ("as e e.args[0]") is a pain to read due to no clear
>> separation, just whitespace.
>
> I don't disagree, but it's less bad than some of the other
> alternatives :). It's also not quite as bad when not using the
> exception (which I suspect would be somewhat more common):
>
> foo = try bar() except BarException "default"

Looks like a bug magnet, if nothing else. Are you allowed newlines in
that construct?

ChrisA

Chris Angelico

unread,
Feb 13, 2014, 5:24:54 PM2/13/14
to python-ideas
On Fri, Feb 14, 2014 at 9:22 AM, Greg Ewing <greg....@canterbury.ac.nz> wrote:
> Chris Angelico wrote:
>>
>> phone = "Unknown" if except KeyError else addressbook[name]
>
>
> -42. My brain gets totally derailed when it hits "if except";
> it parses that bit as a syntax error.

Yeah, and it reads backwards anyway. I don't particularly like that syntax.

ChrisA

Greg Ewing

unread,
Feb 13, 2014, 5:25:12 PM2/13/14
to python...@python.org
spir 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.]

I don't think it shows that at all. Which is the normal
case and which is the exceptional one depends entirely
on how the condition is expressed.

--
Greg

Greg Ewing

unread,
Feb 13, 2014, 6:26:01 PM2/13/14
to python...@python.org
Terry Reedy wrote:

> >>> (seq or ['default'])[0]
> 'default'
>
> (Python's precedence rules make the parentheses optional).

Um, no, they don't:

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

In any case, this only works for an extremely special case
(an index of 0), and can hardly be seen as an alternative
to the proposed except-expression.

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

This is an even *more* special case, since it only works
if you know that the only way the dict can possibly fail
to contain the key is if it's completely empty.

--
Greg

Jan Kaliszewski

unread,
Feb 13, 2014, 6:37:42 PM2/13/14
to python...@python.org
My 3 cents (not proposed yet, AFAIK):


1. Simple Variant:

get_it() except (IndexError: None)

2. Variant with 'as':

get_it() except (OSError as exc: exc.errno)

3. Variant with multiple exceptions:

get_it() except (FileNotFound: 0,
OSError as exc: exc.errno,
Exception: None)

Cheers.
*j

Greg Ewing

unread,
Feb 13, 2014, 6:37:50 PM2/13/14
to python-ideas
Amber Yust wrote:
> Actually. What if we just reused 'try'?
>
> foo = bar() except BazException try 'qux'

This suggests that trying 'qux' may somehow fail to work,
which is not the intended meaning at all.

--
Greg

spir

unread,
Feb 14, 2014, 2:41:23 AM2/14/14
to python...@python.org
On 02/13/2014 11:25 PM, Greg Ewing wrote:
> spir 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.]
>
> I don't think it shows that at all. Which is the normal
> case and which is the exceptional one depends entirely
> on how the condition is expressed.

Say it differently: the condition should single out the special case, not the
normal one;

d

Georg Brandl

unread,
Feb 14, 2014, 4:30:16 AM2/14/14
to python...@python.org
Am 14.02.2014 08:41, schrieb spir:
> On 02/13/2014 11:25 PM, Greg Ewing wrote:
>> spir 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.]
>>
>> I don't think it shows that at all. Which is the normal
>> case and which is the exceptional one depends entirely
>> on how the condition is expressed.
>
> Say it differently: the condition should single out the special case, not the
> normal one;

And that is also just your opinion.

Georg

Rob Cliffe

unread,
Feb 14, 2014, 7:33:09 AM2/14/14
to python...@python.org
I propose the syntax

x = try entries[0] except IndexError: None

Advantages:

(1) Similar to the current try ... except syntax, so meaning immediately
obvious.

(2) Allows all the current (and future??) syntax of except clauses:
x = try get_it() except IOError as e: e.errno
x = try get_it() except (OSError, IOError): None
x = try entries[0] except NameError: ProgramError[1] except
IndexError: None

(3) Unambiguous: in the last example the second "except" traps an
IndexError that occurs during the evaluation of "entries[0]", not during
the evaluation of "ProgramError[1]" (the latter would be written with a
second "try" before "ProgramError[1], not that I would recommend doing
it). An "except" refers to the expression following the nearest
preceding "try". I.e. there is no "dangling except" problem.

(4) Straightforward to parse. The leading "try" immediately tells the
parser what to expect. And the "except"s and colons are unambiguous
delimiters. Ditto for a human reader.

(5) No new keyword, or strained use of an existing keyword, needed.

It would be illegal to have a "try" expression without at least one
"except", just as is it currently illegal to have a "try" statement
without at least one "except" or "finally".

Rob Cliffe


On 13/02/2014 23:37, Greg Ewing wrote:
> Amber Yust wrote:
>> Actually. What if we just reused 'try'?
>>
>> foo = bar() except BazException try 'qux'
>
> This suggests that trying 'qux' may somehow fail to work,
> which is not the intended meaning at all.
>

Jan Kaliszewski

unread,
Feb 14, 2014, 4:29:26 PM2/14/14
to python...@python.org, Nick Coghlan
13.02.2014 13:50, Nick Coghlan wrote:

> 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

Please append also my proposal from another branch of this thread:

> 1. Simple Variant:
>
> get_it() except (IndexError: None)
>
> 2. Variant with 'as':
>
> get_it() except (OSError as exc: exc.errno)
>
> 3. Variant with multiple exceptions:
>
> get_it() except (FileNotFound: 0,
> OSError as exc: exc.errno,
> Exception: None)

Cheers.
*j

Greg Ewing

unread,
Feb 14, 2014, 5:20:13 PM2/14/14
to python...@python.org
Here's another one:

things[i] (except IndexError: 42)

This has the advantage of putting the colon inside parens,
where it's less likely to get confused with other uses of
colons in the same line (by humans, if not by the computer).

Also it might be useful to be able to say

things.remove(i) (except ValueError: pass)

which would be equivalent to

things.remove(i) (except ValueError: None)

but would read more smoothly in cases where you're not
interested in the value of the expression.

--
Greg

Nick Coghlan

unread,
Feb 14, 2014, 7:46:27 PM2/14/14
to Jan Kaliszewski, python...@python.org
On 15 February 2014 07:29, Jan Kaliszewski <z...@chopin.edu.pl> wrote:
> 13.02.2014 13:50, Nick Coghlan wrote:
>
>> 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
>
>
> Please append also my proposal from another branch of this thread

There's currently no volunteer to write a PEP - my post was just an
illustration of the kinds of things such a PEP would need to consider.
Until there is such a volunteer, the many syntax variants will remain
scattered throughout the thread, and we'll likely end up rehashing the
discussion in a couple of years time.

Note that writing a PEP isn't that complicated - the general process
is covered in PEP 1, and the PEP editors take care of most of the
details of checking that the markup is correct and then actually
posting it on python.org (by committing it to the PEPs repo).

So, if anyone would like to write up this discussion, it will involve
a few things:

1. Having enough time to follow the discussion and update it with new
variants and any new open questions that come up
2. Being willing to read old PEPs for similar ideas (notably PEP 308
which added conditional expressions, but also those for yield from,
the with statement, etc), and use those as a guide to the kind of
things that need to be accounted for in a new syntax proposal
3. Being able to write up the proposal in such a way that it presents
a clear rationale (based on the thread - in particular noting the
uneven impact the lack of such a feature is having on function API
designs), a clear *semantic* proposal (what does the new construct
actually do, what is the scope of any name bindings involved, what
scope do subexpressions evaluate in, etc), and then a presentation of
the (many) syntactic proposals.

Cheers,
Nick.

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

Chris Angelico

unread,
Feb 14, 2014, 11:24:31 PM2/14/14
to python...@python.org
On Sat, Feb 15, 2014 at 11:46 AM, Nick Coghlan <ncog...@gmail.com> wrote:
> There's currently no volunteer to write a PEP - my post was just an
> illustration of the kinds of things such a PEP would need to consider.
> Until there is such a volunteer, the many syntax variants will remain
> scattered throughout the thread, and we'll likely end up rehashing the
> discussion in a couple of years time.

I'll do up a PEP. If nothing else, it can be rejected and thus retain
on record what's been said here.

It'll be my first PEP. Let's see how bad a job I make of it :)

ChrisA

Stephen J. Turnbull

unread,
Feb 12, 2014, 11:57:56 PM2/12/14
to Ben Finney, python...@python.org
Ben Finney writes:
> Ben Finney <ben+p...@benfinney.id.au> writes:
> > Ram Rachum <ram.r...@gmail.com> writes:

> > > Here's an idea that would help shortening code.

Shortening code is not a win in Python in general. Other things
equal, OK, but clarity comes first. ITSM Raymond's comment about
simplifying *other* APIs is the right way to get support from
python-dev.

> > > 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"

Why not spell it the same way as in a try statement?

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

The "as" clause would be required, so "as" always binds to the
immediately preceding "except", and iterated it should associate as
"(this except ErrorA as that) except ErrorB as other" rather than
"this except ErrorA as (that except ErrorB as other)" IMO.

I don't think it reads very well, though. The statement form (1)
emphasizes the main operation compared to the "try", and (2) suggests
that catching an exception is quite a heavy operation compared to
execution without an exception, which is true.

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

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

This has incorrect semantics. The correct semantics would be

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

I assume.

Chris Angelico

unread,
Feb 15, 2014, 12:37:57 AM2/15/14
to python-ideas
On Thu, Feb 13, 2014 at 3:57 PM, Stephen J. Turnbull <ste...@xemacs.org> wrote:
> Why not spell it the same way as in a try statement?
>
> response_text = request('http://whatever.com').text except HttpError as "can't access data"
>
> The "as" clause would be required, so "as" always binds to the
> immediately preceding "except", and iterated it should associate as
> "(this except ErrorA as that) except ErrorB as other" rather than
> "this except ErrorA as (that except ErrorB as other)" IMO.
>
> I don't think it reads very well, though. The statement form (1)
> emphasizes the main operation compared to the "try", and (2) suggests
> that catching an exception is quite a heavy operation compared to
> execution without an exception, which is true.

Compared to the block try/except syntax, "as" would have to mean "bind
the exception to this name before going into the exception-handling
block", which is quite different from your proposal. I can mention it
in the PEP if you like, though.

ChrisA

Ben Finney

unread,
Feb 15, 2014, 1:09:17 AM2/15/14
to python...@python.org
"Stephen J. Turnbull" <ste...@xemacs.org>
writes:

> Ben Finney writes:
> > try:
> > response_text = request('http://whatever.com').text
> > except HttpError:
> > "Can't access data"
>
> This has incorrect semantics. The correct semantics would be
>
> try:
> response_text = request('http://whatever.com').text
> except HttpError:
> response_text = "Can't access data"
>
> I assume.

You assume correctly; I wrote the above code too hastily. Thanks for the
correction.

--
\ “Shepherds … look after their sheep so they can, first, fleece |
`\ them and second, turn them into meat. That's much more like the |
_o__) priesthood as I know it.” —Christopher Hitchens, 2008-10-29 |
Ben Finney

Stephen J. Turnbull

unread,
Feb 15, 2014, 3:36:44 AM2/15/14
to Ram Rachum, python...@python.org, M.-A. Lemburg
Ram Rachum writes:

> My favorite syntax so far is:

>    x except Exception as e pass e.y

I think that this syntax is overengineering (regardless of the
keywords used).

That is, I think it's reasonable to have a syntax like

 >    x except Exception pass y

for the purpose of passing a specific default (especially because it's
a big step toward getting rid of the nuisance default parameters in
many APIs). But the extended syntax here allows e.y to be the result
of an arbitrary calculation. I think it's better to use the heavier
statement syntax in that case. While I'm no authority on
"Pythonicity", somehow packing so much into the syntax

  x except Exception as e pass e.y

seems to the be kind of thing that the Zen refers to as "complicated".

Stephen J. Turnbull

unread,
Feb 15, 2014, 4:03:06 AM2/15/14
to Chris Angelico, python-ideas
Chris Angelico writes:
> On Thu, Feb 13, 2014 at 3:57 PM, Stephen J. Turnbull <ste...@xemacs.org> wrote:
> > Why not spell it the same way as in a try statement?
> >
> > response_text = request('http://whatever.com').text except HttpError as "can't access data"

> Compared to the block try/except syntax, "as" would have to mean "bind
> the exception to this name before going into the exception-handling
> block", which is quite different from your proposal.

True.

> I can mention it in the PEP if you like, though.

No, please don't. Your point kills it.

My main thing is to avoid encouraging use of "may_raise() except
ExcType as exc WHATEVER default_value". I don't think an expression
should return multiple values through separate channels this way, and
as posted elsewhere I think use of exc *in* the expression is
"complicated".

Chris Angelico

unread,
Feb 15, 2014, 4:26:20 AM2/15/14
to python-ideas
On Sat, Feb 15, 2014 at 8:03 PM, Stephen J. Turnbull <ste...@xemacs.org> wrote:
> My main thing is to avoid encouraging use of "may_raise() except
> ExcType as exc WHATEVER default_value". I don't think an expression
> should return multiple values through separate channels this way, and
> as posted elsewhere I think use of exc *in* the expression is
> "complicated".

Understood, but I can well imagine there'll be plenty of cases where
it makes sense to fold "return value or exception message" into a
single value, possibly including a tag of some sort.

ret = urlopen(addr) except HTTPError as e pass "Oops - "+e.reason

So it makes good sense to grab the exception and use it in the expression.

Anyway, the PEP's written and submitted to the pep editors, so as soon
as something's posted, the bikeshedding can begin anew :)

ChrisA

Steven D'Aprano

unread,
Feb 15, 2014, 1:11:39 PM2/15/14
to python...@python.org
On Sat, Feb 15, 2014 at 11:20:13AM +1300, Greg Ewing wrote:
> Here's another one:
>
> things[i] (except IndexError: 42)

I believe Jan Kaliszewski independently came up with the same syntax
earlier, which is a good sign. Two people suggesting the same thing is
promising.

Jan also suggested that this syntax allows binding the exception:

things[i] (except IndexError as exc: exc.args)

and multiple except terms:

things[i] (except IndexError as exc: exc.args,
except NameError: "missing",
except KeyError: None,
)


One might also catch multiple exceptions in a single term:

things[i] (except IndexError,KeyError as exc: exc.args)


It's a tiny bit unusual to have a colon that doesn't introduce a block,
but only a tiny bit. There is precedent:

lambda x, y: (x+y)/(x*y)


This suggests that perhaps the parentheses aren't needed unless you have
multiple except parts:

things[i] (except IndexError, KeyError as exc: exc.args)
things[i] except IndexError, KeyError as exc: exc.args


but I think they ought to be compulsory if you use multiple excepts. And
of course they are useful for continuing over multiple lines.

I think this syntax looks good when used in compound expressions:

mylist = [23, lambda x: x+1, things[i] except IndexError: 42, ""]

result = function(a, b except NameError: "undefined", c)

result = function(a, b, c) except ValueError: float('nan')

if something(x) except TypeError: None:
block


Dicts are problematic. Should the dict colon bind more or less strongly
than the except colon? I suggest we follow the same rule as for lambda:

adict = {lambda x: x+1: "value",
key+1 except TypeError: 23: "value",
}


Here is a torture-test for the syntax: can we combine it with an
if-expression? I think we can, although you may need parentheses to
disambiguate the expression:

something(x) (except TypeError: a if condition else b)

((something(x) if x else other(x)) (except ValueError: -1)

something(x) if x else (other(x) except ValueError: -1)


Trying to do too much in a single expression is never exactly
*beautiful*, but it can be read.

This does look a tiny bit like a function call, especially if you delete
the space between the leading expression and the opening bracket:

# ugly, don't do this
things[i](except IndexError: 42)

but that's not actually ambiguous, since the keyword except cannot be an
argument to a function.

I like this. I think this is the first non-sucky syntax I've seen (sorry
to everyone who proposed sucky syntax *wink*).



> This has the advantage of putting the colon inside parens,
> where it's less likely to get confused with other uses of
> colons in the same line (by humans, if not by the computer).
>
> Also it might be useful to be able to say
>
> things.remove(i) (except ValueError: pass)
>
> which would be equivalent to
>
> things.remove(i) (except ValueError: None)
>
> but would read more smoothly in cases where you're not
> interested in the value of the expression.

Certainly not! pass implies that *no return result is generated at all*,
which is not possible in Python. Returning None is the right thing to
do.



--
Steven

Philipp A.

unread,
Feb 15, 2014, 2:24:09 PM2/15/14
to Steven D'Aprano, Python-Ideas

hmm i still don’t like the colon. everywhere else in python, it means “new block follows”

and i’m sure nobody here wants to allow the following?

value = hovercraft() except EelsException:
   remove_eels()
   no_eels  #this is assigned to “value” if we have too many eels

i like it in coffeescript and scala, but it’s not used in python, so we shouldn’t introduce it.

neither should we introduce a colon that can’t be followed by a block.

if we wanted the colon in any case, we’d need to do:

winner = germans_win() except EurekaException: return greeks

value = hovercraft() except EelsException:
   remove_eels()
   return no_eels

but i’m still partial to stomach_content = eat() except ThinMintError pass explode()

Amber Yust

unread,
Feb 15, 2014, 2:38:06 PM2/15/14
to Philipp A., python...@python.org

Not everywhere. As previously mentioned, lambdas use a colon which is followed by an expression, not a block.

Steven D'Aprano

unread,
Feb 15, 2014, 2:57:31 PM2/15/14
to python...@python.org
On Sat, Feb 15, 2014 at 08:24:09PM +0100, Philipp A. wrote:
> hmm i still don’t like the colon. everywhere else in python, it means “new
> block follows”

That is incorrect. Did you read my full post? I specifically mentioned
both dicts and lambda, both of which use colons in expressions, and
don't start a new block.


> and i’m sure nobody here wants to allow the following?
>
> value = hovercraft() except EelsException:
> remove_eels()
> no_eels #this is assigned to “value” if we have too many eels

That's not the suggested syntax.

To start with, if you want to spread the expression over multiple lines,
you need either line continuation backslashes, or round brackets:

value = hovercraft() (except EelsException:
remove_eels()
)


Secondly, you then place an unexpected "no_eels" statement after the
expression. That will be a syntax error.


> i like it in coffeescript and scala, but it’s not used in python, so we
> shouldn’t introduce it.

What is used in coffeescript and scala?


> neither should we introduce a colon that *can’t* be followed by a block.

Dicts, lambda.


> if we wanted the colon in any case, we’d need to do:
>
> winner = germans_win() except EurekaException: return greeks

Certainly not. Do we write this?

mydict = {1: return 'a', 2: return 'b'}


> value = hovercraft() except EelsException:
> remove_eels()
> return no_eels

This is not the suggested syntax. I suggest you read my post again, and
notice that this is an *expression*. That is the whole point of the
thread! If you want a block made up of multiple statements, use a
try...except statement.


> but i’m still partial to stomach_content = eat() except ThinMintError pass
> explode()

"pass" is a placeholder null statement, it has no relevance to
try...except. You might just as well sensibly say

stomach_content = eat() except ThinMintError import explode()
stomach_content = eat() except ThinMintError del explode()
stomach_content = eat() except ThinMintError class explode()
stomach_content = eat() except ThinMintError def explode()


stomach_content = eat() except ThinMintError pass explode()

In all of these cases, I have picked a random keyword and just tossed it
into the expression. None of them make any sense.

MRAB

unread,
Feb 15, 2014, 4:08:15 PM2/15/14
to python...@python.org
On 2014-02-15 19:57, Steven D'Aprano wrote:
> On Sat, Feb 15, 2014 at 08:24:09PM +0100, Philipp A. wrote:
>> hmm i still don’t like the colon. everywhere else in python, it means “new
>> block follows”
>
> That is incorrect. Did you read my full post? I specifically mentioned
> both dicts and lambda, both of which use colons in expressions, and
> don't start a new block.
>
It's also used in slices.

_______________________________________________

Bruce Leban

unread,
Feb 15, 2014, 4:08:24 PM2/15/14
to Chris Angelico, python-ideas
While I'm generally positive about the idea of an except expression (and favor A except E pass B over any of the alternatives), I think it's worth looking in a different direction.

One of the motivations of this idea is that there are some use cases that are particularly inconvenient. Another is the proliferation of APIs accepting default values.

So instead of a general solution, let me suggest an alternative that addresses specific use cases. I'll write these in terms of an except expression so that they can be directly compared head to head.

a[?b]     <=>   a[b] except (IndexError, TypeError)pass None
a.?b      <=>   a.b except AttributeError pass None
a(?b)     <=>   a(b) except Exception pass None
a or? b   <=>   (a except Exception pass None) or b
a and? b  <=>   (a except Exception pass None) and b

del? a.b  <=>  try:
                   del a.b
               except AtributeError:
                   pass

Of course you can chain these:
a[?b][?c]
a.?b.?c
a or? b or? c

Pros/Cons:
- no option to specify replacement value on an exception
- no option to specify exceptions to catch
- doesn't specifically solve the api default value issue -- and the option for that case a(?b) catches all exceptions rather than specific ones


--- Bruce
Learn how hackers think: http://j.mp/gruyere-security

Note: the syntax could just as easily be a?[b], a?.b, etc.

MRAB

unread,
Feb 15, 2014, 4:11:41 PM2/15/14
to python...@python.org
On 2014-02-15 21:08, MRAB wrote:
> On 2014-02-15 19:57, Steven D'Aprano wrote:
>> On Sat, Feb 15, 2014 at 08:24:09PM +0100, Philipp A. wrote:
>>> hmm i still don’t like the colon. everywhere else in python, it means “new
>>> block follows”
>>
>> That is incorrect. Did you read my full post? I specifically mentioned
>> both dicts and lambda, both of which use colons in expressions, and
>> don't start a new block.
>>
> It's also used in slices.
>
[snip]
I wonder if the reply is going to be: "Well, _apart_ from dicts,
lambdas, and slices, everywhere else in Python...". :-)

Amber Yust

unread,
Feb 15, 2014, 5:22:15 PM2/15/14
to Bruce Leban, python...@python.org

I don't think adding multiple elements of syntax for an incomplete solution makes sense.

Greg Ewing

unread,
Feb 15, 2014, 6:17:47 PM2/15/14
to python...@python.org
Steven D'Aprano wrote:
> This suggests that perhaps the parentheses aren't needed unless you have
> multiple except parts:
>
> things[i] (except IndexError, KeyError as exc: exc.args)
> things[i] except IndexError, KeyError as exc: exc.args

Possibly not even necessary when there are multiple except
clauses, if you don't require a comma between them:

things[i] except IndexError: 42 except KeyError: 17

Parsing may be easier without the parens as well, since
otherwise it looks like a function call when you hit
the '(' until you see the 'except' after it. (I *think*
that Python's parser could be made to handle that, but
I'd have to experiment to find out for sure.)

> Here is a torture-test for the syntax: can we combine it with an
> if-expression? I think we can, although you may need parentheses to
> disambiguate the expression:
>
> something(x) (except TypeError: a if condition else b)

The paren-less version of this would be

something(x) except TypeError: a if condition else b

the interpretation of which would depend on what relative
precedence we decide on between 'except' and 'if'.

Parens can still be used to clarify, though:

(something(x) except TypeError: a) if condition else b

something(x) except TypeError: (a if condition else b)

> This does look a tiny bit like a function call, especially if you delete
> the space between the leading expression and the opening bracket:
>
> # ugly, don't do this
> things[i](except IndexError: 42)

Yes, that's why I'm leaning towards the paren-less version.

--
Greg

Greg Ewing

unread,
Feb 15, 2014, 6:28:28 PM2/15/14
to Python-Ideas
Philipp A. wrote:
> hmm i still don’t like the colon. everywhere else in python, it means
> “new block follows”

No, it doesn't. There are at least two existing exceptions,
lambdas and slice expressions.

> and i’m sure nobody here wants to allow the following?
>
> |value = hovercraft() except EelsException:
> remove_eels()
> no_eels #this is assigned to “value” if we have too many eels
>
> neither should we introduce a colon that /can’t/ be followed by a block.

I don't think anyone is suggesting that. The colons in lambdas
and slice expressions can't be followed by blocks either,
and nobody seems to have difficulty with that.

--
Greg

Greg Ewing

unread,
Feb 15, 2014, 6:37:05 PM2/15/14
to python...@python.org
Steven D'Aprano wrote:
> On Sat, Feb 15, 2014 at 11:20:13AM +1300, Greg Ewing wrote:

>>Also it might be useful to be able to say
>>
>> things.remove(i) (except ValueError: pass)
>>
>>which would be equivalent to
>>
>> things.remove(i) (except ValueError: None)
>
> Certainly not! pass implies that *no return result is generated at all*,
> which is not possible in Python.

Well, it is, kind of -- an implicit None is produced
when you don't specify a return value for a function;
this is a similar thing.

Would it help if it were *only* allow it in a context
where the value of the expression is going to be ignored?

--
Greg

Chris Angelico

unread,
Feb 15, 2014, 6:46:15 PM2/15/14
to python-ideas
On Sun, Feb 16, 2014 at 10:17 AM, Greg Ewing
<greg....@canterbury.ac.nz> wrote:
>> This does look a tiny bit like a function call, especially if you delete
>> the space between the leading expression and the opening bracket:
>>
>> # ugly, don't do this
>> things[i](except IndexError: 42)
>
>
> Yes, that's why I'm leaning towards the paren-less version.

I'm not liking the parenthesized version here, because the 'except'
expression has to know how much of the preceding expression to modify.
With a function call:

expression(args)

the expression is fully evaluated first, and then whatever it returns
gets called; with the except expression, a try block has to be set up
somewhere. This is more similar to if-else than to a function call, in
that the expression before the 'if' isn't evaluated until the
condition has been tested.

Parens could go around the whole thing:

(thing[i] except IndexError: 42)
(1/x if x else "Div by 0")

but not around the except clause:

thing[i] (except IndexError: 42) # Nope
1/x (if x else "Div by 0") # Nope

Incidentally, I'm looking at this being able to chain quite nicely:

((expr except Exception1: default1) except Exception2: default2)

Ideally the peephole optimizer could set up a single try/except
structure for both, but syntactically, I'm seeing this as the way the
operator associates.

I've mailed the first-draft PEP to peps@; is it appropriate to post it
here as well, or should I wait to hear back from peps@?

ChrisA

Chris Angelico

unread,
Feb 15, 2014, 7:06:50 PM2/15/14
to python-ideas
On Sun, Feb 16, 2014 at 10:37 AM, Greg Ewing
<greg....@canterbury.ac.nz> wrote:
> Steven D'Aprano wrote:
>>
>> On Sat, Feb 15, 2014 at 11:20:13AM +1300, Greg Ewing wrote:
>
>
>>> Also it might be useful to be able to say
>>>
>>> things.remove(i) (except ValueError: pass)
>>>
>>> which would be equivalent to
>>>
>>> things.remove(i) (except ValueError: None)
>>
>>
>> Certainly not! pass implies that *no return result is generated at all*,
>> which is not possible in Python.
>
>
> Well, it is, kind of -- an implicit None is produced
> when you don't specify a return value for a function;
> this is a similar thing.
>
> Would it help if it were *only* allow it in a context
> where the value of the expression is going to be ignored?

That's nothing to do with the 'pass' keyword.

def foo():
print("Hello!")

This will return None, and it doesn't have 'pass'.

def foo(x):
if x: pass
return 42

This will not, regardless of the value of x. Python's 'pass' means 'do
nothing', in a place where you contextually need to do something.

ChrisA

MRAB

unread,
Feb 15, 2014, 7:35:59 PM2/15/14
to python...@python.org
You'll also need to note that:

((expr except Exception1: default1) except Exception2: default2)

is not the same as:

(expr except Exception1: default1 except Exception2: default2)

The first will also catch Exception2 if default1 raises it, whereas the
second will catch Exception2 only if expr raises it and it hasn't been
caught by the preceding 'except'.

> Ideally the peephole optimizer could set up a single try/except
> structure for both, but syntactically, I'm seeing this as the way the
> operator associates.
>
> I've mailed the first-draft PEP to peps@; is it appropriate to post it
> here as well, or should I wait to hear back from peps@?
>

Chris Angelico

unread,
Feb 15, 2014, 7:57:03 PM2/15/14
to python-ideas
On Sun, Feb 16, 2014 at 11:35 AM, MRAB <pyt...@mrabarnett.plus.com> wrote:
> You'll also need to note that:
>
>
> ((expr except Exception1: default1) except Exception2: default2)
>
> is not the same as:
>
> (expr except Exception1: default1 except Exception2: default2)
>
> The first will also catch Exception2 if default1 raises it, whereas the
> second will catch Exception2 only if expr raises it and it hasn't been
> caught by the preceding 'except'.

Ooh. Good catch. This is not just an optimization, it's a specific
piece of syntax: chaining 'except' blocks MUST catch only from the
original.

I'm also switching around my Proposal and Alternative Proposals a bit,
as I'm currently leaning towards the colon rather than a keyword.

Lots of edits to the PEP draft, but so far just kept local to my own
computer. At what point (and in what way) should I start sharing those
edits?

ChrisA

Steven D'Aprano

unread,
Feb 15, 2014, 10:35:02 PM2/15/14
to python...@python.org
On Sun, Feb 16, 2014 at 12:35:59AM +0000, MRAB wrote:
> On 2014-02-15 23:46, Chris Angelico wrote:
> >On Sun, Feb 16, 2014 at 10:17 AM, Greg Ewing
> ><greg....@canterbury.ac.nz> wrote:
> >>>This does look a tiny bit like a function call, especially if you delete
> >>>the space between the leading expression and the opening bracket:
> >>>
> >>> # ugly, don't do this
> >>> things[i](except IndexError: 42)
> >>
> >>
> >>Yes, that's why I'm leaning towards the paren-less version.
> >
> >I'm not liking the parenthesized version here, because the 'except'
> >expression has to know how much of the preceding expression to modify.

I don't think this is terribly different from the if-expression. The
parser sees an expression:

1/x ...

and doesn't know it is part of an if-expression until it has read on and
seen the "if":

1/x if x != 0 ...

so I don't expect this to be a problem.


[...]
> >Parens could go around the whole thing:

Of course they can, that's just normal parentheses-as-grouping :-)


> >(thing[i] except IndexError: 42)
> >(1/x if x else "Div by 0")
> >
> >but not around the except clause:
> >
> >thing[i] (except IndexError: 42) # Nope
> >1/x (if x else "Div by 0") # Nope

I disagree about prohibiting this. I think it actually makes it easier
to read in the case of multiple except terms. Since they ought to be
separated by commas, and stylistically they ought to be split
one-per-line, I prefer the bracket-less version when there is only a
single except:

thing(a, b) except ThisError, ThatError: default

and brackets when there are more than one:

thing(a, b) (except ThisError, ThatError: default,
except SpamError, EggsError: something,
except OutOfCheeseError: different_thing,
)


although I'm happy for the parens to be optional in the second case if
the parser can manage it, assuming that the parser can disambigulate all
the various uses of commas.

I can't think of any places where parens are explicitly prohibited. They
used to be prohibited in imports, but that's no longer the case. One
should always be allowed to use parens for grouping and implicit line
continuations, nearly everywhere.


How does this suggested syntax look with Raymond's recent example?
Raymond regretted that max and min now take a "default" argument, as of
Python 3.4. Let's compare:

result = max(some_numbers, key=foo, default=float('nan'))

result = max(some_numbers, key=foo) except ValueError: float('nan')


Looks damn good to me!


> >Incidentally, I'm looking at this being able to chain quite nicely:
> >
> >((expr except Exception1: default1) except Exception2: default2)

This is equivalent to:


try:
try:
result = expr
except Exception1:
result = default1
except Exception2:
result = default2


> You'll also need to note that:
>
> ((expr except Exception1: default1) except Exception2: default2)
>
> is not the same as:
>
> (expr except Exception1: default1 except Exception2: default2)

I disklike the lack of comma between except clauses. I think that ought
to be written as:

(expr except Exception1: default1, except Exception2: default2)

modulo the above argument about parentheses.


> The first will also catch Exception2 if default1 raises it, whereas the
> second will catch Exception2 only if expr raises it and it hasn't been
> caught by the preceding 'except'.

Correct. The two are quite different.


> >Ideally the peephole optimizer could set up a single try/except
> >structure for both, but syntactically, I'm seeing this as the way the
> >operator associates.
> >
> >I've mailed the first-draft PEP to peps@; is it appropriate to post it
> >here as well, or should I wait to hear back from peps@?

I think it is perfectly appropriate to post a draft PEP here.



--
Steven
It is loading more messages.
0 new messages