# Re: [Python-ideas] Start argument for itertools.accumulate() [Was: Proposal: A Reduce-Map Comprehension and a "last" builtin]

```[Raymond Hettinger <raymond.hettin...@gmail.com>]
> ...
> Q. How readable is the proposed code?
> A. Look at the following code and ask yourself what it does:
>
>         accumulate(range(4, 6), operator.mul, start=6)
>
>
>         How many values are emitted?```
```
3

>         What is the first value emitted?

6

>         Are the two sixes related?

No.

>         What is this code trying to accomplish?

It's quite obviously trying to bias the reader against the proposal by
presenting a senseless example ;-)  Assuming there's any real reason
to write that code at all, a better question is whether it's more
comprehensible than

accumulate(itertools.chain([6], range(4, 6)), operator.mul)

> ...
> Q. What would this look like in real code?
> A. We have almost no real-world examples, but here is one from a
> StackExchange post:
>
>         def wsieve():       # wheel-sieve, by Will Ness.
> ideone.com/mqO25A->0hIE89
> ...

By sheer coincidence, I happened to write another yesterday.  This is
from a program looking for the smallest integers that yield new
records for Collatz sequence lengths.  The details don't matter,
except that - like Will Ness's wheel sieve code - it needs to generate
an unbounded increasing sequence of integers with a periodic, but
complicated, sequence of deltas, starting at a more-or-less arbitrary
point.

def buildtab(SHIFT, LIMIT):
...
# Candidates are of the form i*LIMIT + j, for i >= 1 and j in
# goodix.  However, a new record can't be set for a number of
# the form 3k+2:  that's two steps after 2k+1, so the smaller
# 2k+1 has a glide 2 longer.  We want to arrange to never try
# numbers of the form 3k+2 to begin with.
base = 0
ix2 = []
for i in range(3):
base += LIMIT
for ix in goodix:
num = base + ix
if num % 3 != 2:
ix2.append(num)
ix2.append(ix2[0] + 3 * LIMIT)
assert len(ix2) == 2 * len(goodix) + 1
del goodix
deltas = tuple(ix2[i] - ix2[i-1] for i in range(1, len(ix2)))
return tuple(result), ix2[0], deltas

A note on "complicated":  the tuple of deltas here can contain
millions of integers, and that's the smallest length at which it
becomes periodic.

Later:

def coll(SHIFT=24):
...
from itertools import accumulate, chain, cycle
...
LIMIT = 1 << SHIFT
...
abc, first, deltas = buildtab(SHIFT, LIMIT)
...
for num in accumulate(chain([first], cycle(deltas))):
assert num % 3 != 2

As in Will's code, it would be more readable as:

for num in accumulate(cycle(deltas), start=first):

That says what it does pretty clearly, whereas deducing the behavior
from "OK, it's chaining together a singleton list and a cycle, because
...?" is a bit of a head scratcher at first.

That said, if the need came up often, as you noted it's dead easy to
write a helper function to encapsulate the "head scratcher" part, and
with no significant loss of efficiency.

So I'd be -0 overall, _except_ that "chain together a singleton list
and a cycle" is so obscure on the face of it than I'm not sure most
programmers who wanted the functionality of `start=` would ever think
of it.  I'm not sure that I would have, except that I studied Ness's
wheel sieve code a long time ago and the idea stuck.  So that makes me
+0.4.
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/
```