[Python-ideas] Proposal: A Reduce-Map Comprehension and a "last" builtin

Rob Cliffe rob.cliffe at btinternet.com
Wed May 30 20:45:20 EDT 2018

On 30/05/2018 17:05, Peter O'Connor wrote:
> On Thu, May 24, 2018 at 2:49 PM, Steven D'Aprano <steve at pearwood.info 
> <mailto:steve at pearwood.info>> wrote:
>     On Thu, May 24, 2018 at 02:06:03PM +0200, Peter O'Connor wrote:
>     > We could use given for both the in-loop variable update and the
>     variable
>     > initialization:
>     >    smooth_signal =  [average given average=(1-decay)*average +
>     decay*x for
>     > x in signal] given average=0.
>     So in your example, the OUTER "given" creates a local variable in the
>     current scope, average=0, but the INNER "given" inside the
>     comprehension
>     exists inside a separate, sub-local comprehension scope, where you
>     will
>     get an UnboundLocalError when it tries to evaluate
>     (1-decay)*average the
>     first time.
> You're right, having re-thought it, it seems that the correct way to 
> write it would be to define both of them in the scope of the 
> comprehension:
>   smooth_signal =  [average given average=(1-decay)*average + decay*x 
> for x in signal given average=0.]
> This makes sense and follows a simple rule: "B given A" just causes A 
> to be executed before B - that holds true whether B is a variable or a 
> loop declaration like "for x in x_gen".
> So
>     a_gen = (g(a) given a=f(a, x) for x in x_gen given a=0)
> would be a compact form of:
>     def a_gen_func(x_gen):
>         a=0
>         for x in x_gen:
>             a = f(a, x)
>             yield g(a)
>     a_gen = a_gen_func()
[There is a typo here - a_gen_func is defined to take 1 argument but is 
called with none.]

After - *I think* - understanding this, I would try to make the one-line 
clearer by parenthesizing it thus (whether or not the grammar required it):

     a_gen = ( ((g(a) given a=f(a, x)) for x in x_gen) given a=0)

Even then, it would make my head spin if I came across it.  I hope 
no-one would write code like that.

I'm not keen on given, but I must admit that ISTM that this example 
shows something that can only be done with given: putting some 
initialisation, viz. "a=0", into a generator expression.  With :=, it 
would need a trick:
     a_gen = (g( a:=f(a, x) ) for x in [x_gen, a:=0][0] )
     a_gen = (g( a:=f(a, x) ) for a in [0] for x in x_gen] )

Of course, in the case of a list comprehension (as opposed to a genexp), 
the initialisation could be done separately:
     a = 0
     a_list = [g( a:=f(a, x) ) for x in x_gen]

Rob Cliffe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180531/509cad31/attachment-0001.html>

More information about the Python-ideas mailing list