# [Python-ideas] Combining test and assignment, quantifications, and tuple patterns

Alexander Heger python at 2sn.net
Sun Jan 22 06:33:23 CET 2012

```I think one could use the same new construct I proposed for one of the
recent lengthy discussions.  For your convenience, I copy this below, in
disregards of quoting style as it provides an overarching reply to this

You could use

sample <generator expression> as x:
# do something with x
break
else:
# do something else

here the generator expression would be "spam()"

sample y for y in (spam(),) if cond(y) as x:
(...)

or allow a short form

sample y for spam() if cond(y) as x:
(...)

I really think this expressions could add a lot to Python's expressiveness.

As an important note, in the case below, the difference to just a "for
loop" or "generator" would be that <generator expression> is
re-evaluated from scratch every time the loop returns to the sample
statement.  This is what I think would set it apart besides providing
extra uses otherwise.

Admittedly, it is a very complicated construct.
Longer than most good English sentences.
(for which those above are not good examples)

-Alexander

-------- Original Message --------
Subject: Re: [Python-ideas] Fwd: quantifications, and tuple patterns
Date: Mon, 16 Jan 2012 22:00:52 -0600
From: Alexander Heger <python at 2sn.net>
To: python-ideas at python.org

Dear Tom,

> I'm wondering if would make sense to add an "as" clause to the while
and if
> statements, similar to the as clause in the with statement. It would
> essentially retrieve the value field from the witness object described
> above.
>
> This would let one write the main loop in a topological sort (a classic
> workset algorithm) as:
>
>      while any(v for v in vertices if v.incoming_count == 0) as v1:
>          result.append(v)
>          for v2 in v1.outgoing:
>              v2.incoming_count -= 1

I had the same thought going through the thread, but I think the problem
here would be that any is a function that returns a Boolean value.  You
could add a key parameter to return something else, say a tuple of a
truth value and a sample ( any( ..., sample = True) ) but that could
break because

1) "any" could be another function in the context,

2) while would need to deal with special return values in this case

A suggestion to replace the "while any" case is

sample <generator expression> as x:
# do something with x

("sample" may not be the best keyword choice) From the discussion so
far I do not see how to easily avoid having a new keyword

sample v for v in vertices if v.incoming_count == 0 as v1:
# do things with v1

In case you only want one sample, you could add the break statement

sample db.query(page_name=page_name) as page:
render_template(page)
break
else:
error404()

-Alexander

On 01/21/2012 10:51 PM, Steven D'Aprano wrote:
> Nick Coghlan wrote:
>> This suggestion (i.e. embedded assignment in while and if headers) has
>> been made several times, and always come to a grinding halt on one
>> simple problem: it isn't expressive enough.
> [...]
>> The obvious escalation of the suggestion is to adopt "(EXPR as NAME)"
>> as a general purpose embedded assignment expression. However, this
>> idea has problems of its own:
>
>
> I dislike assignment as an expression, and am glad that Python doesn't have
> it. Even though the form "expr as name" avoids the common C gotcha, I am -1 on
>
> I believe it is an unnatural way of writing that obscures the code rather than
> simplifies it. (Sometimes, shorter is not better.) For example, when writing
> code, I might start off by thinking:
>
> if spam() != 'ham':
>       frobulate(spam())
>
>
> Then I would apply DRY and factor out the call to spam:
>
> x = spam()
> if x != 'ham':
>       frobulate(x)
>
>
> This matches my thought processes and corresponds to how you might naturally
> describe the algorithm in English:
>
> Let x equal spam().
> If x != 'ham', then frobulate(x).
>
> The important thing is that you name the thing you care about before using it.
> I think this is a very natural way of writing: first you give the thing you
> care about a name, then you refer to it by name.
>
> Assignment as an expression feels unnatural to me:
>
> if spam() as x != 'ham':
>       frobulate(x)
>
> doesn't really correspond to any natural English order. The assignment is
> dropped in the middle of another clause:
>
> If -- let x = spam() -- x != 'ham', then frobulate(x).
>
> It saves a line, but is not a natural way of writing for me. I would not like
> to read code written that way.
>
> Assignment as an expression also lends itself to writing buggy code like this:
>
> while spam() as x and ham() as y:
>       frobulate(x)
>       glommify(y)
>
> which is wrong, because y won't be defined if x has a true value. The
> alternative would require defeating the short-circuit nature of "and", which
>
> Perhaps the only thing going for it is that it would allow list comprehensions
> to not repeat themselves:
>
> [frobulate(x) for x in seq if frobulate(x)>  0]
> # you could have this
> [y for x in seq if frobulate(x) as y>  0]
>
> Although I prefer to use an inner map:
>
> [y for y in map(frobulate, seq) if y>  0]  # use itertools.imap in Python2
>
>
>

```