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?





On Thu, Apr 5, 2018 at 5:55 PM, Paul Moore <p.f.moore@gmail.com> wrote:
On 5 April 2018 at 22:26, Peter O'Connor <peter.ed.oconnor@gmail.com> wrote:
> I find this a bit awkward, and maintain that it would be nice to have this
> as a built-in language construct to do this natively.  You have to admit:
>
>     smooth_signal = [average = (1-decay)*average + decay*x for x in signal
> from average=0.]
>
> Is a lot cleaner and more intuitive than:
>
>     dev compute_avg(avg, x):
>         return (1 - decay)*avg + decay * x
>
>     smooth_signal =
> itertools.islice(itertools.accumulate(itertools.chain([initial_average],
> signal), compute_avg), 1, None)

Not really, I don't... In fact, factoring out compute_avg() is the
first step I'd take in converting the proposed syntax into something
I'd find readable and maintainable. (It's worth remembering that when
you understand the subject of the code very well, it's a lot easier to
follow complex constructs, than when you're less familiar with it -
and the person who's unfamiliar with it could easily be you in a few
months).

The string of itertools functions are *not* readable, but I'd fix that
by expanding them into an explicit loop:

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

If I have that wrong, it's because I misread *both* the itertools
calls *and* the proposed syntax. But I doubt anyone would claim that
it's possible to misunderstand the explicit loop.

> Moreover, if added with the "last" builtin proposed in the link, it could
> also kill the need for reduce, as you could instead use:
>
>     last_smooth_signal = last(average = (1-decay)*average + decay*x for x in
> signal from average=0.)

    last_smooth_signal = 0
    for x in signal:
        last_smooth_signal = compute_avg(last_smooth_signal, x)

or functools.reduce(compute_avg, signal, 0), if you prefer reduce() -
I'm not sure I do.

Sorry, this example has pretty much confirmed for me that an explicit
loop is *far* more readable.

Paul.