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

Steven D'Aprano steve at pearwood.info
Thu Apr 5 20:29:19 EDT 2018

On Thu, Apr 05, 2018 at 06:24:25PM -0400, Peter O'Connor wrote:

> Well, whether you factor out the loop-function is a separate issue.  Lets
> say we do:
>     smooth_signal = [average = compute_avg(average, x) for x in signal from
>     average=0]
> Is just as readable and maintainable as your expanded version, but saves 4
> lines of code.  What's not to love?

Be careful about asking questions which you think are rhetorical but 
aren't. I can think of at least half a dozen objections to this:

- I'd have no idea what it means without the context of reading 
  this thread.

- That you call it "MapReduce" while apparently doing something
  different from what other people call MapReduce:


- That it uses = as an expression, and the keyword `from` in a 
  weird way that doesn't make sense to me.

- The fact that it requires new syntax, so it isn't backwards
  compatible. Even if I loved it and your proposal was accepted, I
  couldn't use it for at least two years. If I'm writing a library
  that has to work with older versions of Python, probably not for
  a decade.

- That there's no obvious search terms to google for if you come
  across this in code and don't know what it means ("that thing
  that looks like a list comprehension but has from in it").

  (And yes, before you object, list comps have the same downside.)

- The fact that this uses a functional idiom in the first place,
  which many people don't like or get. Especially when they start
  getting complex.

If you haven't already already done so, you ought to read the numerous 
threads from last month on statement local name bindings:


The barrier to adding new syntax to the language is very high. I suspect 
that the *only* chance you have for this sort of comprehension will be 
if one of the name binding proposals is accepted. That will give you 
*half* of what you want:

    [(compute_avg(average, x) as average) for x in signal]

    [(average := compute_avg(average, x)) for x in signal]

only needing a way to give it an initial value. Depending on the way 
comprehensions work, this might be all you need:

    average = 0
    smooth_signal [(average := compute_avg(average, x)) for x in signal]

assuming the := syntax is accepted.

An alternative would be to push for a variant of functools.reduce that 
yields its values lazily, giving us:

    smooth_signal = list(lazy_reduce(compute_avg, x, 0))


More information about the Python-ideas mailing list