
Since this started, I've been using variants of the following in my own code, wrapping `accumulate`: from itertools import accumulate, chain, cycle, islice def accum(iterable, func=None, *, initial=None, skipfirst=False): if initial is not None: iterable = chain([initial], iterable) if func is None: iterable = accumulate(iterable) else: iterable = accumulate(iterable, func) if skipfirst: iterable = islice(iterable, 1, None) return iterable I quite like it! It handles everything that's come up pretty naturally. A difference from what was discussed before: I opposed having a `skipfirst` argument because I didn't want an optional argument that _only_ applied if another optional argument was specified. But `skipfirst` in the above applies regardless of whether `initial` is specified. It turned out to be useful in cases where the _effect_ of `initial` had been gotten instead via slamming the initial value into the first object returned by `iterable`, and then ignored later by a special first case to throw away the first result `accumulate` returned. I'm writing this now because it turned out I used it eight times yesterday, which raised it above background noise level ;-) The first use captures a sequence countless thousands of Python programmers have crafted in various ways by hand: def firstfactor(n, limit=1000): for p in chain([2, 3], accum(cycle([2, 4]), initial=5)): # 2, 3, and integers not divisible by 2 or 3 # 2, 3, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, ... if p*p > n: return n if p > limit: return 0 if n % p == 0: return p The same sequence can be gotten more obscurely via: for p in chain([2, 3], accum(cycle([4, 2]), initial=1, skipfirst=True)): The remaining 7 uses were in transcribing's Lehman's elegant[1] optimization of Fermat's "difference of squares" factorization method: def large(deltas, init): for k in accum(cycle(deltas), initial=init): ... # ints divisible by 30 large([30], 30) # ints divisible by 24 but not by 30 large([24, 24, 24, 48], 24) # ints divisible by 12 but not by 30 or 24 large([24, 48, 24, 24], 12) # ints divisible by 18 but not by 30, 24, or 12 large([36, 72, 36, 36], 18) # ints divisible by 6 but not by 30, 24, 12, or 18 large([36, 24, 12, 24, 12, 24, 36, 12], 6) # ints divisible by 2 but not by 30, 24, 12, 18, or 6 large([2, 4], 2) # ints not divisible by 30, 24, 12, 18, 6, or 2 large([2], 1) Lehman built his sequence generator "by hand" in Algol. where the delta array (`c` in his code) is inherited from `large`'s enclosing scope, and `large()` is passed just the number of deltas and the initial value. A more literal transcription of his code would have used: def large(deltas, init): for k in accum(cycle(deltas), initial=init, skipfirst=True): ... instead with the delta lists rotated and with a different initial value. For example, instead of large([24, 24, 24, 48], 24) above his code uses large([48, 24, 24, 24], -24) The latter needs to ignore the initial (-24) value (except to add it to the first delta: -24 + 48 = 24). That was more natural in context, due to the way he advanced the generated in a `while True:` loop built out of gotos ;-) [1] https://math.boisestate.edu/~liljanab/Cryptology1Fall2013/LehmanFactoring.pd... Historical gloss: Lehman surprisingly transformed Fermat's O(n) method into an O(cube_root(n)) method. I believe that was the first deterministic factoring method known beating trial division's O(sqrt(n)) time. Alas for Lehman, Pollard very soon after published his `rho` method, which runs in probabilistic O(sqrt(p)) time where p is n's smallest prime factor, so in worst-case probabilistic O(fourth_root(n)) time. That relegated Lehman's method to an academic curiosity, although it remains supremely effective if N is the product of two odd primes whose ratio is close to a fraction with "small" numerator and denominator.