<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Wed, May 30, 2018 at 9:02 PM Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Thu, May 31, 2018 at 10:05:33AM +1000, Chris Angelico wrote:<br>
> On Thu, May 31, 2018 at 9:53 AM, Steven D'Aprano <<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>> wrote:<br>
> >> There is no nice, equivalent := version as far as I can tell.<br>
> ><br>
> > Given (pun intended) the fact that you only use transformed_b in a<br>
> > single place, I don't think it is necessary to use := at all.<br>
> ><br>
> > z = {a: transform(b) for b in bs for a in as_}<br>
> ><br>
> > But if you really insist:<br>
> ><br>
> > # Pointless use of :=<br>
> > z = {a: (transformed_b := transform(b)) for b in bs for a in as_}<br>
> ><br>
> <br>
> That's the subtlety of the 'given' usage here. You fell for the same<br>
> trap I did: thinking "it's only used once".<br>
<br>
But it is only used once. I meant once per loop.<br>
<br>
It isn't used in the "for a in as_" inner loop, there's no "if <br>
transformed_b" condition, and it only is used once in the key:value part <br>
of the comprehension.<br>
<br>
<br>
> Actually, what he has is equivalent to:<br>
> <br>
> z = {a: tb for b in bs for tb in [transform(b)] for a in as_}<br>
<br>
Which also uses tb only once, making it a Useless Use Of Assignment.<br>
<br>
(I assume we're not calling transform() for some side-effect, like <br>
logging a message, or erasing your hard drive.)<br>
<br>
<br>
> which means it evaluates transform(b) once regardless of the length of<br>
> as_. <br>
<br>
Ah yes, I see what you mean. Expanded to a loop:<br>
<br>
    for b in bs:<br>
        tb = transform(b)<br>
        for a in as_:<br>
            z[a] = tb<br>
<br>
<br>
It's a little ugly, but there's a trick I already use today:<br>
<br>
py> [x+y for x in "abc" if print(x) or True for y in "de"]<br>
a<br>
b<br>
c<br>
['ad', 'ae', 'bd', 'be', 'cd', 'ce']<br>
<br>
So we can adapt that to assignment instead of output:<br>
<br>
# Don't do this!<br>
z = {a: tb for b in bs if (tb := transform(b)) or True for a in as_}<br>
<br>
But I wouldn't do that. If I'm concerned about the call to transform <br>
(because it is super expensive, say) then I set up a pipeline:<br>
<br>
tbs = (transform(b) for b in bs)  # or map(transform, bs)<br>
z = {a: tb for tb in tbs for a in as_}<br>
<br>
The first generator comprehension can be easily embedded in the other:<br>
<br>
z = {a: tb for tb in (transform(b) for b in bs) for a in as_}<br>
<br>
This makes it super-obvious that transform is called for each b, not for <br>
each (b, a) pair, it works today, and there's no assignment expression <br>
needed at all.<br>
<br>
Assignment expressions should not be about adding yet a third way to <br>
solve a problem that already has a perfectly good solution! ("Expand to <br>
a loop statement" is not a *perfectly* good solution.) To showcase <br>
assignment expressions, we should be solving problems that don't have a <br>
good solution now.<br>
<br>
I'm still not convinced that Neil's "given" example will even work (see <br>
below) but *if he is right* that it does, perhaps that's a good reason <br>
to prefer the simpler := assignment expression syntax, since we're <br>
less likely to use it in confusing ways.<br>
<br>
<br>
> But it's really REALLY not obvious. <br>
<br>
But is it even legal?<br>
<br>
As I understand it, "given" is an expression, not an addition to <br>
comprehension syntax. In that case, I don't think Neil's example will <br>
work at all, for reasons I've already stated.<br>
<br>
If that's not the case, then until somebody tells me what this new <br>
comprehension syntax means, and what it looks like, I have no idea what <br>
is intended.<br>
<br>
Which of these can we write, and what do they do?<br></blockquote><div><br></div><div>Great question.  The trick is to just write them as a sequence of statements without changing the order except to put the expression last.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    [expression given name=something for x in seq]<br></blockquote><div><br></div><div>retval = []</div><div>name = something</div><div>for x in seq:</div><div>    retval.append(expression)</div><div>return retval</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
    [expression for x given name=something in seq]<br></blockquote><div><br></div><div>this one doesn't make sense. </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    [expression for x in seq given name=something]<br>
<br></blockquote><div> </div><div><div>retval = []</div><div>for x in seq:</div><div>    name = something</div><div>    retval.append(expression)</div></div><div>return retval<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    [expression for x in seq if given name=something condition]<br>
<br></blockquote><div>this one doesn't make sense.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    [expression for x in seq if condition given name=something]<br>
<br></blockquote><div>retval = []</div><div>for x in seq:</div><div>    if condition:</div><div>        name = something</div><div>        retval.append(expression)</div><div>return retval</div><div><br></div><div>and of course, the original proposal</div><div><br></div><div>expression given name=something</div><div><br></div><div>means:</div><div><br></div><div>name = something</div><div>retval = expression</div><div>return retval<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
-- <br>
Steve<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
<br>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.<br>
To unsubscribe from this topic, visit <a href="https://groups.google.com/d/topic/python-ideas/keaR3FudcwQ/unsubscribe" rel="noreferrer" target="_blank">https://groups.google.com/d/topic/python-ideas/keaR3FudcwQ/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href="mailto:python-ideas%2Bunsubscribe@googlegroups.com" target="_blank">python-ideas+unsubscribe@googlegroups.com</a>.<br>
For more options, visit <a href="https://groups.google.com/d/optout" rel="noreferrer" target="_blank">https://groups.google.com/d/optout</a>.<br>
</blockquote></div></div>