Re: while expression feature proposal

2012-10-27 Thread Tim Chase
On 10/26/12 19:18, Steven D'Aprano wrote:
 def iterate_until_none_or_false(func, *args, **kwargs):
 while True:
 x = func(*args, **kwargs)
 # Halt if x is None or False, but not other falsey values.
 if x is None or x is False:
 return
 yield x
 
 for x in iterate_until_none_or_false(
 some_function, 1, 2, c, spam=yummy):
 process(x)

I was initially a pretty strong advocate of the proposed as
syntax.  However, the more I've thought about it, the more I keep
coming back to how I've solved the problem in the past which is
mostly what Steven suggests here.  There are so many edge-cases and
warts in the as syntax; most of which disappear with this
generator+forloop:

- yielding/unpacking multiple results  each time: the as syntax
would get really ugly.  Do you test the whole result, or an element
of the result?

- knowing the stopping condition varies: is it when something is
False-ish (an empty string/tuple/list, False, None, etc)?  When it
is None?  When it is exactly False?

- the whole x = (foo(bar) as result) if result else None (or
should that be x = result if (foo(bar) as result) else None?)
style/discussion just really looks ugly to me.  Usually I find
Python code quite beautiful and this syntax doesn't resonate as
beautiful.

To despite my previous excitement, I'm now neutral at best on a
limited while TERM as VAR: syntax.

I know this being persuaded by rational arguments and changing
one's mind thing is rare on the Intarwebs, so I hope I haven't
upset the natural balance of things too greatly. :-)

-tkc





-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Paul Rubin
Dan Loewenherz dloewenh...@gmail.com writes:
 In this case, profile_id is None when the loop breaks. It would be
 much more straightforward (and more Pythonic, IMO), to write:

 client = StrictRedis()
 while client.spop(profile_ids) as profile_id:
 print profile_id

That is pretty loose, in my opinion.  If the loop is supposed to return
a string until breaking on None, the break test should explicitly check
for None rather than rely on an implicit bool conversion that will also
test as false on an empty string.  Code that handles strings should do
the right thing with the empty string.  What you posted relies on an
unstated assumption that the strings that come back are never empty.

 it's a net negative from just doing things the canonical way (with the
 while / assignment pattern).

Yeah, the while/assignment is a bit ugly but it doesn't come up often
enough to be a bad problem, imho.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Chris Angelico
On Fri, Oct 26, 2012 at 5:06 PM, Paul Rubin no.email@nospam.invalid wrote:
 Dan Loewenherz dloewenh...@gmail.com writes:
 In this case, profile_id is None when the loop breaks. It would be
 much more straightforward (and more Pythonic, IMO), to write:

 client = StrictRedis()
 while client.spop(profile_ids) as profile_id:
 print profile_id

 That is pretty loose, in my opinion.  If the loop is supposed to return
 a string until breaking on None, the break test should explicitly check
 for None rather than rely on an implicit bool conversion that will also
 test as false on an empty string.

while (client.spop(profile_ids) as profile_id) is not None:
print profile_id

Why is everyone skirting around C-style assignment expressions as
though they're simultaneously anathema and the goal? :)

But seriously, this new syntax would probably enhance Python somewhat,
but you're going to end up with odd edge cases where it's just as
almost-there as current syntax is for what this will solve. Is it
worth doing half the job?

ChrisA
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Steven D'Aprano
On Fri, 26 Oct 2012 17:23:12 +1100, Chris Angelico wrote:

 Why is everyone skirting around C-style assignment expressions as though
 they're simultaneously anathema and the goal? :)

Only if your goal is to introduce an anathema :P


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Dan Loewenherz
On Thursday, October 25, 2012 11:06:01 PM UTC-7, Paul Rubin wrote:
 Dan Loewenherz dloewenh...@gmail.com writes:
 
  In this case, profile_id is None when the loop breaks. It would be
 
  much more straightforward (and more Pythonic, IMO), to write:
 
 
 
  client = StrictRedis()
 
  while client.spop(profile_ids) as profile_id:
 
  print profile_id
 
 
 
 That is pretty loose, in my opinion.  If the loop is supposed to return
 
 a string until breaking on None, the break test should explicitly check
 
 for None rather than rely on an implicit bool conversion that will also
 
 test as false on an empty string.  Code that handles strings should do
 
 the right thing with the empty string.  What you posted relies on an
 
 unstated assumption that the strings that come back are never empty.
 

I think this is a good point. However, I can't think of any situation where I'd 
want to work with an empty string (in the applications I've worked with, at 
least).

We also don't special case things like this just because x is an empty string. 
If this while EXPR as VAR thing were to move forward, we shouldn't treat the 
truth testing any differently than how we already do. IMO we should write our 
applications with the understanding that '' will return False and work with 
that.

Here's a workaround BTW. Just have that method return a tuple, and do the truth 
testing yourself if you feel it's necessary.

while client.spop(profile_ids) as truthy, profile_id:
if not truthy:
break

print profile_id

Here, client.spop returns a tuple, which will always returns true. We then 
extract the first element and run a truth test on it. The function we use is in 
charge of determining the truthiness.

Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Ian Kelly
On Fri, Oct 26, 2012 at 9:29 AM, Dan Loewenherz dloewenh...@gmail.com wrote:
 while client.spop(profile_ids) as truthy, profile_id:
 if not truthy:
 break

 print profile_id

 Here, client.spop returns a tuple, which will always returns true. We then 
 extract the first element and run a truth test on it. The function we use is 
 in charge of determining the truthiness.

I don't like the idea of testing the first element.  There's a large
element of surprise in doing that, I think.  I would expect the truth
test to be the same with or without the existence of the as clause
there.  That is, you should be able to remove the as clause and have
exactly the same behavior, just without the assignments.  So it would
need to test the entire tuple.

That brings up an interesting additional question in my mind, though.
Should the while loop syntax attempt to perform the assignment on the
very last test, when the expression is false?  I think there is a good
argument for doing so, as it will allow additional inspection of the
false value, if necessary.  In the above, though, if the return value
is false (an empty tuple or None) then the assignment would fail
during unpacking, raising an exception.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Paul Rubin
Dan Loewenherz dloewenh...@gmail.com writes:
 We also don't special case things like this just because x is an empty
 string. If this while EXPR as VAR thing were to move forward, we
 shouldn't treat the truth testing any differently than how we already
 do. IMO we should write our applications with the understanding that
 '' will return False and work with that.

We don't already treat the truth testing any particular way because we
don't have this construction in the language at the moment.  However,
it's well-established in Python that converting a string to a bool
results in False iff the string is empty.

The empty string is a perfectly good string and code that deals with
strings should handle the empty string properly, unless it knows the
string won't be empty.  Basic modularity principles say to avoid putting
such knowledge into more of the code than necessary.  

The conclusion is to not automatically convert the parameter to a bool.
However, if the as can be part of an expression as in Chris Angelico's
post, Chris's suggestion

 while (client.spop(profile_ids) as profile_id) is not None:
 print profile_id

looks good to me.

 while client.spop(profile_ids) as truthy, profile_id:
 if not truthy:
 break

This is ugly on two levels.  First of all, if the .spop() still returns
None at the end of the input, the tuple unpacking will fail.  Second,
the separate test and break defeats the purpose of the while ... as
construction.  Might as well use the current style of assignment and
test inside the loop.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Cameron Simpson
On 26Oct2012 09:10, Paul Rubin no.email@nospam.invalid wrote:
| However, if the as can be part of an expression as in Chris Angelico's
| post, Chris's suggestion
| 
|  while (client.spop(profile_ids) as profile_id) is not None:
|  print profile_id
| 
| looks good to me.

Now this pulls me from a -0 to a +0.5.

Instead of burdening the control constructs with further structure, make
as a binding operation for keeping intermediate results from expressions.

It will work anywhere an expression is allowed, and superficially
doesn't break stuff that exists if as has the lowest precedence.

Any doco would need to make it clear that no order of operation is
implied, so that this:

  x = 1
  y = (2 as x) + x

does not have a defined answer; might be 2, might be 3. Just like any
other function call with side effects.

Speaking for myself (of course!), I definitely prefer this to adding
as as a post expression struction on if/while/etc.

I'm not +1 because to my mind it still presents a way for
assignment/binding to not be glaringly obvious at the left hand side of
an expression.

It would probably mean folding the except/with as uses back into
expressions and out of the control-structural part of the grammar. I can't
see that that would actually break any existing code though - anyone else?

Cheers,
-- 
Cameron Simpson c...@zip.com.au

UNIX was not designed to stop you from doing stupid things, because that
would also stop you from doing clever things.   - Doug Gwyn
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Ian Kelly
On Fri, Oct 26, 2012 at 4:03 PM, Cameron Simpson c...@zip.com.au wrote:
 It will work anywhere an expression is allowed, and superficially
 doesn't break stuff that exists if as has the lowest precedence.

Please, no.  There is no need for it outside of while expressions, and
anywhere else it's just going to be bad practice.  Even if it's
considered an expression, let's only allow it in while expressions.

 Any doco would need to make it clear that no order of operation is
 implied, so that this:

   x = 1
   y = (2 as x) + x

 does not have a defined answer; might be 2, might be 3. Just like any
 other function call with side effects.

Actually, the docs are clear that expressions are evaluated left to
right, so the expected result of the above would be 4.

 It would probably mean folding the except/with as uses back into
 expressions and out of the control-structural part of the grammar. I can't
 see that that would actually break any existing code though - anyone else?

Yes it would, because the meaning is a bit different in both of those
cases.  For except, the result of the expression (an exception class
or tuple of classes) is not stored in the target; the exception
*instance* is.  Similarly for with, the result of the expression is
not stored; the result of calling its __enter__ method is, which is
often but not always the same thing.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Devin Jeanpierre
On Fri, Oct 26, 2012 at 1:12 AM, Dan Loewenherz dloewenh...@gmail.com wrote:
 It seems the topic of this thread has changed drastically from the original 
 message.

 1) while EXPR as VAR in no way says that EXPR must be a boolean value. In 
 fact, a use case I've run into commonly in web development is popping from a 
 redis set. E.g.

 client = StrictRedis()
 while True:
 profile_id = client.spop(profile_ids)
 if not profile_id:
 break
 print profile_id

 In this case, profile_id is None when the loop breaks. It would be much 
 more straightforward (and more Pythonic, IMO), to write:

 client = StrictRedis()
 while client.spop(profile_ids) as profile_id:
 print profile_id

For loops are pythonic. You can do this in Python today:

client = StrictRedis()
for profile_id in iter(lambda: client.spop(profile_ids), None):
pass

I would like a better iter(), rather than a better while loop. It is
irritating to pass in functions that take arguments, and it is
impossible to, say, pass in functions that should stop being iterated
over when they return _either_ a None or a, say, False.

-- Devin
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Devin Jeanpierre
On Fri, Oct 26, 2012 at 2:23 AM, Chris Angelico ros...@gmail.com wrote:
 while (client.spop(profile_ids) as profile_id) is not None:
 print profile_id

 Why is everyone skirting around C-style assignment expressions as
 though they're simultaneously anathema and the goal? :)

Why should these two statements behave differently? :(

with foo() as bar: bar.baz()
with (foo() as bar): bar.baz()

I don't understand why everyone is so attached to this as syntax.
It's confusing because it behaves subtly differently than how it works
in with, and it puts the variable on the wrong side of the
assignment operator.

(I've always been partial to :=, personally.)

-- Devin
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Tim Chase
On 10/26/12 17:03, Cameron Simpson wrote:
 On 26Oct2012 09:10, Paul Rubin no.email@nospam.invalid wrote:
 |  while (client.spop(profile_ids) as profile_id) is not None:
 
 Now this pulls me from a -0 to a +0.5.
 
 Any doco would need to make it clear that no order of operation is
 implied, so that this:
 
   x = 1
   y = (2 as x) + x
 
 does not have a defined answer; might be 2, might be 3. Just like any
 other function call with side effects.

I really don't like undefined (or underdefined) specs.  If it was to
be PEP'd out, I'd want to address as many edge cases as possible.
Such as

  y = (2 as x) + (3 as x) + (4 as x)
  y = (2 as x) + 4 as x
  y = booleanish and (2 as x) or (4 as x)
  y = booleanish and 2 or 4 as x
  y = (2 as x) if booleanish else (3 as x)
  y = (2 as x) if booleanish else (3 as z)

regardless of how $PEJORATIVE, that's a dumb thing to do! it is.

I hate C for how underdefined a lot of corners are. (amongst my
hatreds of C are such diverse elements as: underdefined corners, a
pitiful standard library, the ease of shooting yourself in the foot,
...)

 I'm not +1 because to my mind it still presents a way for
 assignment/binding to not be glaringly obvious at the left hand side of
 an expression.

I think this is why I like it in the while (and could be twisted
into accepting it for if) because it also introduces an
implied/actual scope for which the variable is intended.  In an
arbitrary evaluation/assignment, it's much easier to lose the
definition nature of it at the top of a block.

-tkc





-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Dan Loewenherz
On Fri, Oct 26, 2012 at 4:12 PM, Devin Jeanpierre jeanpierr...@gmail.comwrote:


 For loops are pythonic. You can do this in Python today:

 client = StrictRedis()
 for profile_id in iter(lambda: client.spop(profile_ids), None):
 pass

 I would like a better iter(), rather than a better while loop. It is
 irritating to pass in functions that take arguments, and it is
 impossible to, say, pass in functions that should stop being iterated
 over when they return _either_ a None or a, say, False.


You can kind of do this by creating a class implementing __eq__ and passing
that in as the sentinal to the iter method.

class FlexibleEquality(object):
def __init__(self, *candidates):
self.candidates = candidates

def __eq__(self, other):
return any(other == candidate for candidate in self.candidates)

client = StrictRedis()
for profile_id in iter(lambda: client.spop(profile_ids),
FlexibleEquality(False, None)):
pass

But this is yucky. I'd much rather have something a bit more clear to the
reader. The above is somewhat convoluted. I would far prefer for while
EXPR as VAR to run through the results of EXPR as an iterable and continue
the loop if any of the values in the iterable is truthy, maybe passing only
the first value of the iterable to VAR. Gives maximum flexibility with the
cleanest resulting code.

 client.spop(profile_ids) # conditional succeeds, '123' passed to
profile_id
'123', True
 client.spop(profile_ids) # conditional succeeds, '' passed to
profile_id
'', True
 client.spop(profile_ids) # conditional fails
'', False

Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Devin Jeanpierre
On Fri, Oct 26, 2012 at 6:03 PM, Cameron Simpson c...@zip.com.au wrote:
 Any doco would need to make it clear that no order of operation is
 implied, so that this:

   x = 1
   y = (2 as x) + x

 does not have a defined answer; might be 2, might be 3. Just like any
 other function call with side effects.

But function calls with side effects _do_ have a defined order of
evaluation. Left to right. And the answer should be 4.

http://docs.python.org/reference/expressions.html#evaluation-order

 def set_(d, k, v):
... d[k] = v
... return v
...
 d = {}
 set_(d, 'x', 1)
1
 set_(d, 'y', set_(d, 'x', 2) + d['x'])
4

-- Devin
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Cameron Simpson
On 26Oct2012 19:41, Devin Jeanpierre jeanpierr...@gmail.com wrote:
| On Fri, Oct 26, 2012 at 6:03 PM, Cameron Simpson c...@zip.com.au wrote:
|  Any doco would need to make it clear that no order of operation is
|  implied, so that this:
| 
|x = 1
|y = (2 as x) + x
| 
|  does not have a defined answer; might be 2, might be 3. Just like any
|  other function call with side effects.
| 
| But function calls with side effects _do_ have a defined order of
| evaluation. Left to right.
| And the answer should be 4.
| http://docs.python.org/reference/expressions.html#evaluation-order

No. Separate _expressions_ are evaluated left to right.

So this:

  f(1), f(2)

calls f(1) first, then f(2). But this:

  f(1) + f(2)

need not do so. Counter-documentation welcomed, but the doco you cite
does not define an order for the second example above.

| 
|  def set_(d, k, v):
| ... d[k] = v
| ... return v
| ...
|  d = {}
|  set_(d, 'x', 1)
| 1
|  set_(d, 'y', set_(d, 'x', 2) + d['x'])
| 4

That may just be a coincidence of implementation - there's no special
reason to change the evaluation order form the lexical order there, but
expression optimisers should have a free hand generally.

Cheers,
-- 
Cameron Simpson c...@zip.com.au

Acceptance Testing: Dropping your mods straight into the production
environment to see if the users will accept them.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Devin Jeanpierre
On Fri, Oct 26, 2012 at 7:41 PM, Dan Loewenherz dloewenh...@gmail.com wrote:
-- snip insanity --

 But this is yucky. I'd much rather have something a bit more clear to the
 reader.

That's why I said I wanted a better iter, not some equality-overriding
object strawman thing.

I was thinking more like this:

for profile_id in iter(None)(client.spop, profile_ids):

or alternatively:

for profile_id in iter(bool)(client.spop, profile_ids):

Or perhaps either as keyword arguments (which is the only reason I
curried iter).

The interesting case for in-place assignment is not here. This is a
trivial case. It's in cases like this:

while True:
x = foo(bar())
if x is None: break
if x % 2 == 0: break

print x

Imagine doing that with iter. :)

-- Devin
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Devin Jeanpierre
On Fri, Oct 26, 2012 at 7:56 PM, Cameron Simpson c...@zip.com.au wrote:
 No. Separate _expressions_ are evaluated left to right.

 So this:

   f(1), f(2)

 calls f(1) first, then f(2). But this:

   f(1) + f(2)

 need not do so. Counter-documentation welcomed, but the doco you cite
 does not define an order for the second example above.

Actually, it does. Both f(1) and f(2) are separate (sub-)expressions
in f(1) + f(2). More to the point, it gives the following example:

In the following lines, expressions will be evaluated in the
arithmetic order of their suffixes:
...
expr1 + expr2 * (expr3 - expr4)

I sympathize with your concern, though. Order of evaluation is very
bitey, and it's better to be safe than sorry.

-- Devin
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Cameron Simpson
On 26Oct2012 18:26, Tim Chase s...@thechases.com wrote:
| On 10/26/12 17:03, Cameron Simpson wrote:
|  On 26Oct2012 09:10, Paul Rubin no.email@nospam.invalid wrote:
|  |  while (client.spop(profile_ids) as profile_id) is not None:
|  
|  Now this pulls me from a -0 to a +0.5.
|  
|  Any doco would need to make it clear that no order of operation is
|  implied, so that this:
|  
|x = 1
|y = (2 as x) + x
|  
|  does not have a defined answer; might be 2, might be 3. Just like any
|  other function call with side effects.
| 
| I really don't like undefined (or underdefined) specs.  If it was to
| be PEP'd out, I'd want to address as many edge cases as possible.

I would not. Big time. One of the reasons C is so successful as a
lower level language is that by defining only what is needed to be
defined to make it _possible_ to get predictable and useful behaviour,
maximum flexibility is left for implementation to adapt to particular
environments as freely as possible.

Pinning down all the corner cases is in general a bad idea, IMO. Every
corner case you pin down is an early decision for inflexibility that may
later prove to be illfounded.

Specify what _needs_ to be specified to achieve the required effect.
And stay the hell away from things that only constraint outcomes while
not providing the required effect.

To take an obvious counter example: your stance would encourage defining
the iteration order of dictionary keys. To no good purpose, merely to
present definition of _all_ operations instead of just the necessary
operations.

| Such as
|   y = (2 as x) + (3 as x) + (4 as x)
|   y = (2 as x) + 4 as x

I would want these to be ambiguous, myself.

|   y = booleanish and (2 as x) or (4 as x)
|   y = booleanish and 2 or 4 as x
|   y = (2 as x) if booleanish else (3 as x)
|   y = (2 as x) if booleanish else (3 as z)

None of these is ambiguous. The second one could be harder to read and
want some brackets purely for clarity, but it is perfectly well defined
in outcome already.

| regardless of how $PEJORATIVE, that's a dumb thing to do! it is.

No, sometimes dumb things should remain bad ideas. Defining them to all
just makes them no longer obviously bad ideas, merely subtly bad ideas.
And subtly bad ideas are worse!

| I hate C for how underdefined a lot of corners are. (amongst my
| hatreds of C are such diverse elements as: underdefined corners, a
| pitiful standard library, the ease of shooting yourself in the foot,
| ...)

The C standard library was pretty good for when it came out. And the higher
up the available facilities tree you go the more choices there are about
how something should be done. C is still one of my favourite languages
in its domain, though I haven't used it much for several years.

If you're uncomfortable with C, try to stay away from it. (I try to stay
away from C++ and its bretheren for similar reasons.)

|  I'm not +1 because to my mind it still presents a way for
|  assignment/binding to not be glaringly obvious at the left hand side of
|  an expression.
| 
| I think this is why I like it in the while (and could be twisted
| into accepting it for if) because it also introduces an
| implied/actual scope for which the variable is intended.

A conceptual scope, sure. Presumably not a real one in Python...

| In an
| arbitrary evaluation/assignment, it's much easier to lose the
| definition nature of it at the top of a block.

I'm not sure I agree here. Code example?

Cheers,
-- 
Cameron Simpson c...@zip.com.au

Everything should be made as simple as possible, but no simpler.
- Albert Einstein
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Cameron Simpson
On 27Oct2012 10:56, I wrote:
| On 26Oct2012 19:41, Devin Jeanpierre jeanpierr...@gmail.com wrote:
| | But function calls with side effects _do_ have a defined order of
| | evaluation. Left to right.
| | And the answer should be 4.
| | http://docs.python.org/reference/expressions.html#evaluation-order
| 
| No. Separate _expressions_ are evaluated left to right.
[...]
| need not do so. Counter-documentation welcomed, but the doco you cite
| does not define an order for the second example above.
[...]

On 26Oct2012 16:48, Ian Kelly ian.g.ke...@gmail.com wrote:
|  does not have a defined answer; might be 2, might be 3. Just like any
|  other function call with side effects.
| Actually, the docs are clear that expressions are evaluated left to
| right, so the expected result of the above would be 4.

Ian, Devin, my apologies. You're right, the docs are clear and my brain
is foggy. So, no ambiguity about that with the suggested as operator.
-- 
Cameron Simpson c...@zip.com.au

Well, if you didn't struggle so much, you wouldn't get rope burns.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Cameron Simpson
On 26Oct2012 16:48, Ian Kelly ian.g.ke...@gmail.com wrote:
| On Fri, Oct 26, 2012 at 4:03 PM, Cameron Simpson c...@zip.com.au wrote:
|  It will work anywhere an expression is allowed, and superficially
|  doesn't break stuff that exists if as has the lowest precedence.
| 
| Please, no.  There is no need for it outside of while expressions, and
| anywhere else it's just going to be bad practice.  Even if it's
| considered an expression, let's only allow it in while expressions.

We might just have to differ here.

|  It would probably mean folding the except/with as uses back into
|  expressions and out of the control-structural part of the grammar. I can't
|  see that that would actually break any existing code though - anyone else?
| 
| Yes it would, because the meaning is a bit different in both of those
| cases.  For except, the result of the expression (an exception class
| or tuple of classes) is not stored in the target; the exception
| *instance* is.  Similarly for with, the result of the expression is
| not stored; the result of calling its __enter__ method is, which is
| often but not always the same thing.

Hmm. Good points. Possibly damning points.

  except (E1, E2) as c as d:

anyone? I should hope not!

I may be back to +0 now:-( +0.5 for being able to get at partial
expression results somehow, -0.1 for the conflict above.

Cheers,
-- 
Cameron Simpson c...@zip.com.au

Every \item command in item_list must have an optional argument.
- Leslie Lamport, LaTeX
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Steven D'Aprano
On Fri, 26 Oct 2012 19:12:17 -0400, Devin Jeanpierre wrote:

 I would like a better iter(), rather than a better while loop. It is
 irritating to pass in functions that take arguments, and it is
 impossible to, say, pass in functions that should stop being iterated
 over when they return _either_ a None or a, say, False.

Write a trivial helper function. Not everything has to be a one-liner or 
a built-in.

def iterate_until_none_or_false(func, *args, **kwargs):
while True:
x = func(*args, **kwargs)
# Halt if x is None or False, but not other falsey values.
if x is None or x is False:
return
yield x

for x in iterate_until_none_or_false(
some_function, 1, 2, c, spam=yummy):
process(x)



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Cameron Simpson
On 26Oct2012 19:19, Devin Jeanpierre jeanpierr...@gmail.com wrote:
| (I've always been partial to :=, personally.)

I'm less so. It is hard to type (on my keyboard anyway, that's a shifted
keystroke followed by an unshifted one). I mank that up often enough
that I would resent it for something as oft used as an assignment.

Visually, yes, it's good. I was happy with it in Pascal and its like,
though I find the succinctness of plain = very attractive given that
it is only available on the left in Python, where it is easy to see and
not prone to mixups with == later in an expression.

Cheers,
-- 
Cameron Simpson c...@zip.com.au

George, discussing a patent and prior art:
Look, this  publication has a date, the patent has a priority date,
can't you just compare them?
Paul Sutcliffe:
Not unless you're a lawyer.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Devin Jeanpierre
On Fri, Oct 26, 2012 at 8:18 PM, Steven D'Aprano
steve+comp.lang.pyt...@pearwood.info wrote:
 I would like a better iter(), rather than a better while loop. It is
 irritating to pass in functions that take arguments, and it is
 impossible to, say, pass in functions that should stop being iterated
 over when they return _either_ a None or a, say, False.

 Write a trivial helper function. Not everything has to be a one-liner or
 a built-in.

You are missing the point. I was suggesting that the use case of new
syntax might be satisfied instead by new functions, which are clearly
preferable to new syntax from the perspective your rebuttal comes
from.

Indeed, one could write those helper functions, and use them, without
any changes to Python being made at all!

-- Devin
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Chris Angelico
On Sat, Oct 27, 2012 at 10:19 AM, Devin Jeanpierre
jeanpierr...@gmail.com wrote:
 On Fri, Oct 26, 2012 at 2:23 AM, Chris Angelico ros...@gmail.com wrote:
 while (client.spop(profile_ids) as profile_id) is not None:
 print profile_id

 Why is everyone skirting around C-style assignment expressions as
 though they're simultaneously anathema and the goal? :)

 Why should these two statements behave differently? :(

 with foo() as bar: bar.baz()
 with (foo() as bar): bar.baz()

 I don't understand why everyone is so attached to this as syntax.
 It's confusing because it behaves subtly differently than how it works
 in with, and it puts the variable on the wrong side of the
 assignment operator.

 (I've always been partial to :=, personally.)

I'm not attached to as, myself. It puts the variable at the wrong
end, and feels backward compared to a convention that exists elsewhere
in the language (regular variable assignment). This is a much stronger
backwardness issue than the Python ternary operator (which is only
backward in comparison to other languages).

Personally, I'm quite happy with assignment itself being an
expression. But since that's unlikely to be directly accepted in
Python, I would be looking for something as general as possible -
something that can truly be used _anywhere_ - rather than a specific
while-statement enhancement. Capturing partial expression results is
an extremely convenient thing to do.

ChrisA
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Paul Rubin
Steven D'Aprano steve+comp.lang.pyt...@pearwood.info writes:
 There's no need for it *inside* of while expressions. It doesn't add to 
 the expressiveness of the language, or increase the power of the 
 language, or help people write correct code. It saves one trivial line of 
 code in some, but not all, while loops, at the cost of increasing the 
 complexity of the language and parser.

I'm maybe +0.25 on the suggestion but it does save more than one line in
the places where it's useful, plus improves clarity.  You get to write
 
   while (foo() as x) is not None:
   ...

instead of

  while True:
x = foo()
if x is not None:
   break
...

which is much uglier.  Maybe there are even times when you want

   while (left() as x) != (right() as y): ...

that is even messier when expanded out.

There was also the cascaded regexp match example, that happens regularly
in real code and that I've hacked various workarounds for, or wished for
a Maybe monad.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 01:39 schrieb Ian Kelly:

On Wed, Oct 24, 2012 at 5:08 PM, Paul Rubin no.email@nospam.invalid wrote:

from itertools import dropwhile

j = dropwhile(lambda j: j in selected,
  iter(lambda: int(random() * n), object()))
  .next()

kind of ugly, makes me wish for a few more itertools primitives, but I
think it expresses reasonably directly what you are trying to do.


Nice, although a bit opaque.  I think I prefer it as a generator expression:

j = next(j for j in iter(partial(randrange, n), None) if j not in selected)


This generator never ends. If it meets a non-matching value, it just 
skips it and goes on.


The dropwhile expression, however, stops as soon as the value is found.

I think

# iterate ad inf., because partial never returns None:
i1 = iter(partial(randrange, n), None)
# take the next value, make it None for breaking:
i2 = (j if j in selected else None for j in i1)
# and now, break on None:
i3 = iter(lambda: next(i2), None)

would do the job.


Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Paul Rudin
Paul Rubin no.email@nospam.invalid writes:

 kind of ugly, makes me wish for a few more itertools primitives

JOOI, do you have specific primitives in mind?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 00:26 schrieb Cameron Simpson:


If I could write this as:

   if re_FUNKYPATTERN.match(test_string) as m:
 do stuff with the results of the match, using m

then some cascading parse decisions would feel a bit cleaner. Where I
current have this:

   m = re_CONSTRUCT1.match(line)
   if m:
 ... handle construct 1 ...
   else:
 m = re_CONSTRUCT2.match(line)
 if m:
   ... handle construct 2 ...
 else:
   m = re_CONSTRUCT3.match(line)

I could have this:

   if re_CONSTRUCT1.match(line) as m:
 ... handle construct 1 ...
   elif re_CONSTRUCT2.match(line) as m:
 ... handle construct 2 ...
   elif re_CONSTRUCT3.match(line) as m:


I would do

for r in re_CONSTRUCT1, re_CONSTRUCT2, re_CONSTRUCT3:
m = r.match(line)
if m: handle_construct

or maybe

actions = {re_CONSTRUCT1: action1, ...}

def matching(line, *rr):
for r in rr:
m = r.match(line)
if m: yield r; return

for r in matching(line, *actions.keys()):
actions[r]()
break
else:
raise NoActionMatched() # or something like that

Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 06:50 schrieb Terry Reedy:


Keep in mind that any new syntax has to be a substantial improvement in
some sense or make something new possible. There was no new syntax in
3.2 and very little in 3.3.


I would consinder this at least as new substantial than

yield_from it

as opposed to

for i in it: yield i

- although I think that was a good idea as well.

Although there are quite easy ways to do so, I would appreciate 
something like the proposed


   while EXPR as VAR: use VAR
   if EXPR as VAR: use VAR

Of course it is possible to construct a respective workaround such as

def maybe_do_that():
if moon == full:
with something as val:
yield val

for val in maybe_do_that():
bla

but I would consider this as an abuse of the generator concept.

Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 09:21 schrieb Thomas Rachel:


I think

# iterate ad inf., because partial never returns None:
i1 = iter(partial(randrange, n), None)
# take the next value, make it None for breaking:
i2 = (j if j in selected else None for j in i1)
# and now, break on None:
i3 = iter(lambda: next(i2), None)

would do the job.


But, as I read it now again, it might be cleaner to create an own 
generator function, such as


def rand_values(randrange, n, selected):
# maybe: selected = set(selected) for the not in
while True:
val = partial(randrange, n)
if val not in selected: break
yield val

for value in rand_values(...):

or, for the general case proposed some posings ago:

def while_values(func, *a, **k):
while True:
val = func(*a, **k):
if not val: break
yield val

Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Steven D'Aprano
On Thu, 25 Oct 2012 11:52:31 +0200, Thomas Rachel wrote:

 Am 25.10.2012 06:50 schrieb Terry Reedy:
 
 Keep in mind that any new syntax has to be a substantial improvement in
 some sense or make something new possible. There was no new syntax in
 3.2 and very little in 3.3.
 
 I would consinder this at least as new substantial than
 
  yield_from it
 
 as opposed to
 
  for i in it: yield i
 
 - although I think that was a good idea as well.

Then I think you have misunderstood the purpose of yield from. The fact 
that you can replace the two lines:

for value in another_iterator:
yield iterator

with a one-liner yield from another_iterator is the least important use-
case for yield-from. If that was the only use-case, it probably would not 
have been allowed, because it adds complication to the language for a 
trivial gain.

The purpose of yield-from is to transfer control to another coroutine, 
not to save one trivial line of code.

[quote]
However, if the subgenerator is to interact properly with the caller in 
the case of calls to send(), throw() and close(), things become 
considerably more difficult. As will be seen later, the necessary code is 
very complicated, and it is tricky to handle all the corner cases 
correctly.

A new syntax will be proposed to address this issue. In the simplest use 
cases, it will be equivalent to the above for-loop, but it will also 
handle the full range of generator behaviour, and allow generator code to 
be refactored in a simple and straightforward way.
[end quote]

http://www.python.org/dev/peps/pep-0380/


yield from is a *huge* win in terms of correctness and power, not just 
a trivial saving in lines of code. while expr as var is not.


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Antoon Pardon
On 25-10-12 06:50, Terry Reedy wrote:
 On 10/24/2012 7:19 PM, Evan Driscoll wrote:
 On 10/24/2012 05:26 PM, Cameron Simpson wrote:
 But I'm still -0 on it, because it supplants the glaringly obvious:

m = ...

 assignment with the far less in your face:

possibly-long-expr as m

 and I think it would get quite heavily used, to the detriment of
 assignment readability in general. At present the nature of most
 effects
 is at the left. An assignment is obvious on the left, an
 if/with/while/etc
 is visible at the left.

 In the interest of brainstorming, what about

 while VAR from EXPR:

 or something like that? I don't think I like 'from' on a couple counts,
 but there's probably some word that fits.

 The op wondered if these proposals have been made before. They have
 been, and have been rejected. Some of the discussion has been on
 python-ideas list. But go ahead and brainstorm and discuss.

 Keep in mind that any new syntax has to be a substantial improvement
 in some sense or make something new possible. There was no new syntax
 in 3.2 and very little in 3.3.

If I recal correctly at one point the following was accepted:

do:
suite
while expr:
suite

But it was later discarded because of lack of a champion or something
like that.

-- 
Antoon Pardon
 
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 12:50 schrieb Steven D'Aprano:


Then I think you have misunderstood the purpose of yield from.


Seems so. As I have not yet switched to 3.x, I haven't used it till now.


[quote]
However, if the subgenerator is to interact properly with the caller in
the case of calls to send(), throw() and close(), things become
considerably more difficult. As will be seen later, the necessary code is
very complicated, and it is tricky to handle all the corner cases
correctly.


Ok, thanks.


Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Grant Edwards
On 2012-10-24, Cameron Simpson c...@zip.com.au wrote:

| I must say I really like the parity of Dan's
|   while EXPR as VAR:
|  BLOCK
| proposal with the with statement.

 Well, it's nice. But usually EXPR will be a boolean.

I guess that depends on what sort of programs you write.  In my
experience, EXPR is usually a read from a file/socket/pipe that
returns '' on EOF. If VAR is not '', then you process, then you
process it inside the loop.

-- 
Grant Edwards   grant.b.edwardsYow! We're going to a
  at   new disco!
  gmail.com
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Grant Edwards
On 2012-10-25, Terry Reedy tjre...@udel.edu wrote:

 The op wondered if these proposals have been made before. They have 
 been, and have been rejected. Some of the discussion has been on 
 python-ideas list. But go ahead and brainstorm and discuss.

 Keep in mind that any new syntax has to be a substantial improvement in 
 some sense or make something new possible. There was no new syntax in 
 3.2 and very little in 3.3.

I think the new syntax should be introduced in 2.00.  There were a
number of other big changes between 1.52 and 2.00, so that seems like
a good spot to put this change.

-- 
Grant Edwards   grant.b.edwardsYow! !!  I am having fun!!!
  at   
  gmail.com
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 16:15 schrieb Grant Edwards:


I guess that depends on what sort of programs you write.  In my
experience, EXPR is usually a read from a file/socket/pipe that
returns '' on EOF. If VAR is not '', then you process, then you
process it inside the loop.


Right. The same as in

if regex.search(string) as match:
process it

But with

def if_true(expr):
if expr: yield expr

you can do

for match in if_true(regex.search(string)):
process it

But the proposed if ... as ...: statment woulkd be more beautiful by far.

Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Ian Kelly
On Thu, Oct 25, 2012 at 1:21 AM, Thomas Rachel
nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa...@spamschutz.glglgl.de
wrote:
 j = next(j for j in iter(partial(randrange, n), None) if j not in
 selected)


 This generator never ends. If it meets a non-matching value, it just skips
 it and goes on.

next() only returns one value.  After it is returned, the generator is
discarded, whether it has ended or not.  If there were no valid values
for randrange to select, then it would descend into an infinite loop.
But then, so would the dropwhile and the original while loop.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Ian Kelly
On Thu, Oct 25, 2012 at 3:52 AM, Thomas Rachel
nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa...@spamschutz.glglgl.de
wrote:
 Am 25.10.2012 06:50 schrieb Terry Reedy:


 Keep in mind that any new syntax has to be a substantial improvement in
 some sense or make something new possible. There was no new syntax in
 3.2 and very little in 3.3.


 I would consinder this at least as new substantial than

 yield_from it

 as opposed to

 for i in it: yield i

 - although I think that was a good idea as well.

Except that those two are not exactly identical, because yield from
also properly delegates sent data and exceptions to the sub-generator.
 The actual equivalent code for yield from expr(), as given in the
PEP, is 39 lines long.  This is a substantial feature, not just a
little syntactic sugar.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Ian Kelly
On Thu, Oct 25, 2012 at 10:36 AM, Ian Kelly ian.g.ke...@gmail.com wrote:
 On Thu, Oct 25, 2012 at 1:21 AM, Thomas Rachel
 nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa...@spamschutz.glglgl.de
 wrote:
 j = next(j for j in iter(partial(randrange, n), None) if j not in
 selected)


 This generator never ends. If it meets a non-matching value, it just skips
 it and goes on.

 next() only returns one value.  After it is returned, the generator is
 discarded, whether it has ended or not.  If there were no valid values
 for randrange to select, then it would descend into an infinite loop.
 But then, so would the dropwhile and the original while loop.

To demonstrate that the code does in fact return:

 selected = set(range(5))
 n = 10
 from functools import partial
 from random import randrange
 j = next(j for j in iter(partial(randrange, n), None) if j not in selected)
 j
5
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Terry Reedy

On 10/25/2012 6:50 AM, Steven D'Aprano wrote:

On Thu, 25 Oct 2012 11:52:31 +0200, Thomas Rachel wrote:


Am 25.10.2012 06:50 schrieb Terry Reedy:


Keep in mind that any new syntax has to be a substantial improvement in
some sense or make something new possible. There was no new syntax in
3.2 and very little in 3.3.


I would consinder this at least as new substantial than

  yield_from it

as opposed to

  for i in it: yield i

- although I think that was a good idea as well.


Then I think you have misunderstood the purpose of yield from. The fact
that you can replace the two lines:

for value in another_iterator:
 yield iterator

with a one-liner yield from another_iterator is the least important use-
case for yield-from. If that was the only use-case, it probably would not
have been allowed, because it adds complication to the language for a
trivial gain.

The purpose of yield-from is to transfer control to another coroutine,
not to save one trivial line of code.

[quote]
However, if the subgenerator is to interact properly with the caller in
the case of calls to send(), throw() and close(), things become
considerably more difficult. As will be seen later, the necessary code is
very complicated, and it is tricky to handle all the corner cases
correctly.

A new syntax will be proposed to address this issue. In the simplest use
cases, it will be equivalent to the above for-loop, but it will also
handle the full range of generator behaviour, and allow generator code to
be refactored in a simple and straightforward way.
[end quote]

http://www.python.org/dev/peps/pep-0380/


yield from is a *huge* win in terms of correctness and power, not just
a trivial saving in lines of code. while expr as var is not.


r = yield from g

is equivalent to about 40 lines of code as given here
http://www.python.org/dev/peps/pep-0380/#formal-semantics

It took the developers several tries to first get a version that worked 
and then to work out the exact details.


--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Thomas Rachel

Am 25.10.2012 18:36 schrieb Ian Kelly:

On Thu, Oct 25, 2012 at 1:21 AM, Thomas Rachel
nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa...@spamschutz.glglgl.de
wrote:

j = next(j for j in iter(partial(randrange, n), None) if j not in
selected)



This generator never ends. If it meets a non-matching value, it just skips
it and goes on.


next() only returns one value.  After it is returned, the generator is
discarded, whether it has ended or not.  If there were no valid values
for randrange to select, then it would descend into an infinite loop.
But then, so would the dropwhile and the original while loop.


You are completely right. My solution was right as well, but didn't 
match the problem...


Yours does indeed return one random value which is guaranteed not to be 
in selected.


Mine returns random values until the value is not in selected. I just 
misread the intention behind the while loop...



Thomas
--
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Dan Loewenherz
It seems the topic of this thread has changed drastically from the original 
message.

1) while EXPR as VAR in no way says that EXPR must be a boolean value. In 
fact, a use case I've run into commonly in web development is popping from a 
redis set. E.g.

client = StrictRedis()
while True:
profile_id = client.spop(profile_ids)
if not profile_id:
break
print profile_id

In this case, profile_id is None when the loop breaks. It would be much more 
straightforward (and more Pythonic, IMO), to write:

client = StrictRedis()
while client.spop(profile_ids) as profile_id:
print profile_id

2) Although not originally intended, I kind of like the if statement change 
proposed later in this thread. It certainly makes sense, since both while and 
if are conditional statements that are commonly followed by an assignment (or 
vice versa).

3) I don't think the use case I brought up is solved nicely by wrapping a 
function / lambda in a generator and using a for loop. E.g.

def helper(f):
value = f()
if value:
yield value

for profile_id in helper(lambda: client.spop(profile_ids)):
print profile_id

This works too, I guess

def helper(f, *args, **kwargs):
value = f(*args, **kwargs)
if value:
yield value

for profile_id in helper(client.spop, profile_ids):
print profile_id

Either way, it adds too much mental overhead. Every developer on a project has 
to now insert x lines of code before a for loop or import a helper method from 
some module, and do this every time this pattern reappears. It's not something 
I would want to do in one of my projects, since it makes things harder to 
understand. So all in all, it's a net negative from just doing things the 
canonical way (with the while / assignment pattern).

Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


while expression feature proposal

2012-10-24 Thread Dan Loewenherz
Hi all,

This is my first post to this group--I'm not subscribed, so please CC
me in responses.

So I'm sure a lot of you have run into the following pattern. I use it
all the time and it always has felt a bit awkward due to the duplicate
variable assignment.

VAR = EXPR
while VAR:
BLOCK
VAR = EXPR

I'm curious what the possibility of adding the following to Python as
syntactic sugar:

while EXPR as VAR:
BLOCK

Apologies if that has been proposed before. I searched the archives
and couldn't find any mention of it.

Best,
Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Ian Kelly
On Wed, Oct 24, 2012 at 2:40 PM, Dan Loewenherz dloewenh...@gmail.com wrote:
 So I'm sure a lot of you have run into the following pattern. I use it
 all the time and it always has felt a bit awkward due to the duplicate
 variable assignment.

 VAR = EXPR
 while VAR:
 BLOCK
 VAR = EXPR

The idiomatic way to do this is:

while True:
VAR = EXPR
if not VAR:
break
BLOCK
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Tim Chase
On 10/24/12 16:34, Ian Kelly wrote:
 On Wed, Oct 24, 2012 at 2:40 PM, Dan Loewenherz dloewenh...@gmail.com wrote:
 So I'm sure a lot of you have run into the following pattern. I use it
 all the time and it always has felt a bit awkward due to the duplicate
 variable assignment.

 VAR = EXPR
 while VAR:
 BLOCK
 VAR = EXPR
 
 The idiomatic way to do this is:
 
 while True:
 VAR = EXPR
 if not VAR:
 break
 BLOCK

It may be idiomatic, but that doesn't stop it from being pretty
ugly.  I must say I really like the parity of Dan's

  while EXPR as VAR:
 BLOCK

proposal with the with statement.  It also doesn't fall prey to
the mistaken-assignment vs. intentional-assignment found in most
C-like languages.  I could see a pretty reasonable PEP coming from this.

-tkc






-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Paul Rubin
Dan Loewenherz dloewenh...@gmail.com writes:
 VAR = EXPR
 while VAR:
 BLOCK
 VAR = EXPR

for VAR in iter(lambda: EXPR, None):
   BLOCK

where the termination sentinel might be False or '' or whatever instead
of None.  Of course if EXPR is a callable, there's no lambda.

 while EXPR as VAR:
 BLOCK

This is kind of nice.  I wonder if it could generalize with somehow,
i.e. use the context manager for EXPR if it has one.  Or maybe iter
could be generalized so you could pass an arbutrary predicate as
termination condition, instead of a single sentinel value.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Cameron Simpson
On 24Oct2012 16:54, Tim Chase python.l...@tim.thechases.com wrote:
| On 10/24/12 16:34, Ian Kelly wrote:
|  On Wed, Oct 24, 2012 at 2:40 PM, Dan Loewenherz dloewenh...@gmail.com 
wrote:
|  So I'm sure a lot of you have run into the following pattern. I use it
|  all the time and it always has felt a bit awkward due to the duplicate
|  variable assignment.
| 
|  VAR = EXPR
|  while VAR:
|  BLOCK
|  VAR = EXPR
|  
|  The idiomatic way to do this is:
|  
|  while True:
|  VAR = EXPR
|  if not VAR:
|  break
|  BLOCK
| 
| It may be idiomatic, but that doesn't stop it from being pretty
| ugly.

Yes, but more flexible because it accomodates loops where the natural
place for the test is partway through the loop instead of right at the
top, which is quite common.

| I must say I really like the parity of Dan's
|   while EXPR as VAR:
|  BLOCK
| proposal with the with statement.

Well, it's nice. But usually EXPR will be a boolean. If you're inside
the loop you know it's true and don't need VAR. Of course, the glaring
counter example is things like regexp tests. I have a heap of code like
this:

  m = re_FUNKYPATTERN.match(test_string)
  if m:
do stuff with the results of the match, using m

If I could write this as:

  if re_FUNKYPATTERN.match(test_string) as m:
do stuff with the results of the match, using m

then some cascading parse decisions would feel a bit cleaner. Where I
current have this:

  m = re_CONSTRUCT1.match(line)
  if m:
... handle construct 1 ...
  else:
m = re_CONSTRUCT2.match(line)
if m:
  ... handle construct 2 ...
else:
  m = re_CONSTRUCT3.match(line)

I could have this:

  if re_CONSTRUCT1.match(line) as m:
... handle construct 1 ...
  elif re_CONSTRUCT2.match(line) as m:
... handle construct 2 ...
  elif re_CONSTRUCT3.match(line) as m:

which is both more concise and also doesn't step inward.

But I'm still -0 on it, because it supplants the glaringly obvious:

  m = ...

assignment with the far less in your face:

  possibly-long-expr as m

and I think it would get quite heavily used, to the detriment of
assignment readability in general. At present the nature of most effects
is at the left. An assignment is obvious on the left, an if/with/while/etc
is visible at the left.

With statements and except statements have concrete use cases for the
as part that aren't doable without it, but the while/if...as form
can always be written in the current convention.

Cheers,
-- 
Cameron Simpson c...@zip.com.au
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Paul Rubin
Cameron Simpson c...@zip.com.au writes:
   if re_FUNKYPATTERN.match(test_string) as m:
 do stuff with the results of the match, using m

  class memo:
 def __call__(f, *args, **kw):
self.result = f(*args, **kw)

  m = memo()

  if result(re_FUNKYPATTERN.match, test_string):
   do stuff with the results of the match,
   using m.result

then

  if re_CONSTRUCT1.match(line) as m:
... handle construct 1 ...
  elif re_CONSTRUCT2.match(line) as m:
... handle construct 2 ...
  elif re_CONSTRUCT3.match(line) as m:

becomes

   if m(re_CONSTRUCT1.match, line):
 .. handle construct 1 ...
   elif m(re_CONSTRUCT2.match, line):
 .. handle construct 2 ...
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Chris Angelico
On Thu, Oct 25, 2012 at 9:26 AM, Cameron Simpson c...@zip.com.au wrote:
 If I could write this as:

   if re_FUNKYPATTERN.match(test_string) as m:
 do stuff with the results of the match, using m

Then you'd be right there with C-like languages where assignment is an
expression :)

while (tok = strtok(blah,blah)) ... do something with tok ...

ChrisA
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Paul Rubin
Paul Rubin no.email@nospam.invalid writes:
   class memo:
  def __call__(f, *args, **kw):
 self.result = f(*args, **kw)

obviously add

  return self.result 
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Tim Chase
On 10/24/12 17:26, Cameron Simpson wrote:
 On 24Oct2012 16:54, Tim Chase python.l...@tim.thechases.com wrote:
 | On 10/24/12 16:34, Ian Kelly wrote:
 |  The idiomatic way to do this is:
 |  
 |  while True:
 |  VAR = EXPR
 |  if not VAR:
 |  break
 |  BLOCK
 | 
 | It may be idiomatic, but that doesn't stop it from being pretty
 | ugly.
 
 Yes, but more flexible because it accomodates loops where the natural
 place for the test is partway through the loop instead of right at the
 top, which is quite common.

Just like the with doesn't stop you from using a try/finally block
to do something similar, you can still write mid-loop exits as code
currently exists.  The proposed syntax just makes coming from other
languages easier to translate.

 | I must say I really like the parity of Dan's
 |   while EXPR as VAR:
 |  BLOCK
 | proposal with the with statement.
 
 Well, it's nice. But usually EXPR will be a boolean.

I think the most common use-cases are boolean'ish.  The falsehood
means stop, but the truthiness value is not merely True.  The common
use-case I hit is the

  f = file('foo.bin')
  while True:
data = f.read(CHUNK_SIZE)
if not data: break
process(data) #not just data=True

which tidily becomes

  while f.read(CHUNK_SIZE) as data:
process(data)

   m = re_FUNKYPATTERN.match(test_string)
   if m:
 do stuff with the results of the match, using m
 
 If I could write this as:
 
   if re_FUNKYPATTERN.match(test_string) as m:
 do stuff with the results of the match, using m

I'm -0 on this.  I don't like the pattern, but I'm not sure the if
CONDITION as FOO syntax yields nearly the functional  readable
improvement of while THING as FOO.

 then some cascading parse decisions would feel a bit cleaner. Where I
 current have this:
 
   m = re_CONSTRUCT1.match(line)
   if m:
 ... handle construct 1 ...
   else:
 m = re_CONSTRUCT2.match(line)
 if m:
   ... handle construct 2 ...
 else:
   m = re_CONSTRUCT3.match(line)

For those, I often end up putting the regexps in a list and
iterating accordingly (which I have done multiple times):

  regexes = [
re_one,
re_two,
re_three,
]
  for regex in regexes:
m = regex.match(line)
if m:
  handle(m)
  break
  else:
doh()

Granted, it does expect that you want to handle the results
uniformly, but this could (usually) be mitigated with a dispatch
function as well

  regex_dispatches = [
(re_one, handle1),
(re_two, handle2),
(re_three, handle3),
]
  for regex, fn in regex_dispatches:
m = regex.match(line):
if m:
  fn(m, extra_context)
  break
  else:
doh()


 But I'm still -0 on it, because it supplants the glaringly obvious:
 
   m = ...
 
 assignment with the far less in your face:
 
   possibly-long-expr as m

If it were replacing standard assignment, I'd be as off-the-charts
-1 as possible.  Yech.  But when cued by the while and
indentation, it's not quite so bad.  It still feels yuckyâ„¢ in an
if, but I find the improvement in the while is certainly worthwhile.


 With statements and except statements have concrete use cases for the
 as part that aren't doable without it, but the while/if...as form
 can always be written in the current convention.

The syntax for the with *could* have been something like

  with foo = file(foo.txt):
for line in foo:
  pass

but the as was chosen and I think it makes sense in the context.

-tkc

(To me, the if CONDITION as VAR feels much like the ternary
evaluation:

  x = foo if bar else baz

which made it into official syntax; I find the while CONDITION as
VAR much more readable/valuable in light of both)




-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Ian Kelly
On Wed, Oct 24, 2012 at 3:54 PM, Tim Chase
python.l...@tim.thechases.com wrote:
 It may be idiomatic, but that doesn't stop it from being pretty
 ugly.  I must say I really like the parity of Dan's

   while EXPR as VAR:
  BLOCK

 proposal with the with statement.  It also doesn't fall prey to
 the mistaken-assignment vs. intentional-assignment found in most
 C-like languages.  I could see a pretty reasonable PEP coming from this.

Often though the while test is not a simple boolean test of VAR.  For example:

j = int(random() * n)
while j in selected:
j = int(random() * n)

It also doesn't flow quite as naturally.  with x as y is
grammatically correct English.  while x as y is not, and I wonder
how easily it might be confused for while x is y, which is valid
Python and means something completely different.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Cameron Simpson
On 25Oct2012 09:40, Chris Angelico ros...@gmail.com wrote:
| On Thu, Oct 25, 2012 at 9:26 AM, Cameron Simpson c...@zip.com.au wrote:
|  If I could write this as:
| 
|if re_FUNKYPATTERN.match(test_string) as m:
|  do stuff with the results of the match, using m
| 
| Then you'd be right there with C-like languages where assignment is an
| expression :)
| 
| while (tok = strtok(blah,blah)) ... do something with tok ...

Well, yes, that's the core convenience of the suggested syntax.
But without the =/== accident opportunity.
But with another assignment that doesn't look like an asisgnment syntax.

Like I said, I'm -0.
-- 
Cameron Simpson c...@zip.com.au

Be smart, be safe, be paranoid.
- Ryan Cousineau, cour...@compdyn.com DoD#863, KotRB, KotKWaWCRH
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Cameron Simpson
On 24Oct2012 15:37, Paul Rubin no.email@nospam.invalid wrote:
| Cameron Simpson c...@zip.com.au writes:
|if re_FUNKYPATTERN.match(test_string) as m:
|  do stuff with the results of the match, using m
| 
|   class memo:
|  def __call__(f, *args, **kw):
| self.result = f(*args, **kw)
| 
|   m = memo()
|   if result(re_FUNKYPATTERN.match, test_string):
|do stuff with the results of the match,
|using m.result
| 
| then
| 
|   if re_CONSTRUCT1.match(line) as m:
| ... handle construct 1 ...
|   elif re_CONSTRUCT2.match(line) as m:
| ... handle construct 2 ...
|   elif re_CONSTRUCT3.match(line) as m:
| 
| becomes
| 
|if m(re_CONSTRUCT1.match, line):
|  .. handle construct 1 ...
|elif m(re_CONSTRUCT2.match, line):
|  .. handle construct 2 ...

Cute. Not sure I like it, but cute:-)
-- 
Cameron Simpson c...@zip.com.au

If you do not read the paper, you are uninformed. If you do read the
paper, you are misinformed. - Mark Twain
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Paul Rubin
Ian Kelly ian.g.ke...@gmail.com writes:
 j = int(random() * n)
 while j in selected:
 j = int(random() * n)

from itertools import dropwhile

j = dropwhile(lambda j: j in selected,
 iter(lambda: int(random() * n), object()))
 .next()

kind of ugly, makes me wish for a few more itertools primitives, but I
think it expresses reasonably directly what you are trying to do.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re: while expression feature proposal

2012-10-24 Thread Evan Driscoll
On 10/24/2012 05:26 PM, Cameron Simpson wrote:
 But I'm still -0 on it, because it supplants the glaringly obvious:
 
   m = ...
 
 assignment with the far less in your face:
 
   possibly-long-expr as m
 
 and I think it would get quite heavily used, to the detriment of
 assignment readability in general. At present the nature of most effects
 is at the left. An assignment is obvious on the left, an if/with/while/etc
 is visible at the left.

In the interest of brainstorming, what about

   while VAR from EXPR:

or something like that? I don't think I like 'from' on a couple counts,
but there's probably some word that fits.

Evan



signature.asc
Description: OpenPGP digital signature
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Ian Kelly
On Wed, Oct 24, 2012 at 5:08 PM, Paul Rubin no.email@nospam.invalid wrote:
 from itertools import dropwhile

 j = dropwhile(lambda j: j in selected,
  iter(lambda: int(random() * n), object()))
  .next()

 kind of ugly, makes me wish for a few more itertools primitives, but I
 think it expresses reasonably directly what you are trying to do.

Nice, although a bit opaque.  I think I prefer it as a generator expression:

j = next(j for j in iter(partial(randrange, n), None) if j not in selected)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-24 Thread Terry Reedy

On 10/24/2012 7:19 PM, Evan Driscoll wrote:

On 10/24/2012 05:26 PM, Cameron Simpson wrote:

But I'm still -0 on it, because it supplants the glaringly obvious:

   m = ...

assignment with the far less in your face:

   possibly-long-expr as m

and I think it would get quite heavily used, to the detriment of
assignment readability in general. At present the nature of most effects
is at the left. An assignment is obvious on the left, an if/with/while/etc
is visible at the left.


In the interest of brainstorming, what about

while VAR from EXPR:

or something like that? I don't think I like 'from' on a couple counts,
but there's probably some word that fits.


The op wondered if these proposals have been made before. They have 
been, and have been rejected. Some of the discussion has been on 
python-ideas list. But go ahead and brainstorm and discuss.


Keep in mind that any new syntax has to be a substantial improvement in 
some sense or make something new possible. There was no new syntax in 
3.2 and very little in 3.3.


--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list