--
--- 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.
> 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 <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 |
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.
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.
Why not use yield instead of else?
foo = something() except BazException yield "bar"
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.
Another possible option:
foo = something() except None for BarException
With possible support for:
foo = something() except e.message for BarException as e
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.
"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.
> 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
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.
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
On Thu, Feb 13, 2014 at 10:36 PM, Paul Moore <p.f....@gmail.com> wrote:Hmm. Stupid idea:
> 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".
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/
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.
On 02/13/2014 07:43 PM, Amber Yust wrote:I like it. Especially because 'try' already works with 'except'. (But note that 'try', like my proposal of 'then', normally introduces a block).
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
On Thu, Feb 13, 2014 at 1:47 PM, spir <denis...@gmail.com> wrote:
On 02/13/2014 07:43 PM, Amber Yust wrote:I like it. Especially because 'try' already works with 'except'. (But note that 'try', like my proposal of 'then', normally introduces a block).
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 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 likefoo = (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)
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
> 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
> 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".
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()
Not everywhere. As previously mentioned, lambdas use a colon which is followed by an expression, not a block.
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.
_______________________________________________
a[?b] <=> a[b] except (IndexError, TypeError)pass Nonea.?b <=> a.b except AttributeError pass Nonea(?b) <=> a(b) except Exception pass Nonea or? b <=> (a except Exception pass None) or ba and? b <=> (a except Exception pass None) and bdel? a.b <=> try:del a.bexcept AtributeError:pass
a[?b][?c]a.?b.?c
a or? b or? c
I don't think adding multiple elements of syntax for an incomplete solution makes sense.