[Python-ideas] A real life example of "given"

Neil Girdhar mistersheik at gmail.com
Thu May 31 03:55:14 EDT 2018


Okay, I though about it some more, and I think I'm mistaken about the
possibility of adding both rules to the grammar since in that case it is
ambiguous whether given binds more tightly to a trailing expression or to
the comp_iter.  It's too bad.

On Wed, May 30, 2018 at 10:50 PM Neil Girdhar <mistersheik at gmail.com> wrote:

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


More information about the Python-ideas mailing list