Batu Lab NotesPractical developer guides

Generate a running total with accumulate

By Batu ยท English technical notes

Also published in our Blogger archive.

itertools.accumulate yields the intermediate values of a running calculation. Given daily signed changes, the default operation is addition, so this example turns (12, -5, 8, -3) into totals (12, 7, 15, 12). It then prints each day beside its corresponding total. This is useful when a report needs the evolving balance rather than only the final sum.

Unlike sum, accumulate yields an iterator of each intermediate result. The code materializes it because the four synthetic values are small and because indexed printing and assertions are convenient. For a long stream, consume the iterator incrementally instead. The assertions prove the expected arithmetic for these values; they do not prove that an input feed is complete, correctly ordered, or semantically valid. Decide separately whether negative totals, missing days, decimal rounding, or an opening balance are acceptable for the domain.

itertools.accumulate was added in Python 3.2. Passing a function changes the operation: operator.mul creates cumulative products. The initial keyword was added in Python 3.8 and prefixes an opening value, but the example uses neither. accumulate does not promise a specific numeric type beyond applying the chosen operation, so choose types such as decimal.Decimal when the domain requires their behavior.

AI-assistance disclosure: this article was drafted with AI assistance and uses fixed synthetic changes.

Source: Python itertools.accumulate documentation.

from itertools import accumulate

changes = (12, -5, 8, -3)
running_totals = tuple(accumulate(changes))

assert running_totals == (12, 7, 15, 12)
assert running_totals[-1] == sum(changes)
assert len(running_totals) == len(changes)

for day, total in enumerate(running_totals, start=1):
    print(f"day={day}, total={total}")
day=1, total=12
day=2, total=7
day=3, total=15
day=4, total=12