Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-135282: change documented signature of itertools.accumulate() #135283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Doc/library/itertools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ streams of infinite length, so they should only be accessed by functions or
loops that truncate the stream.


.. function:: accumulate(iterable[, function, *, initial=None])
.. function:: accumulate(iterable, func=None, *, initial=None)
Copy link
Member

@AA-Turner AA-Turner Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a better alternative, if we decide to change anything. None is misleading: the prose notes that the function defaults to addition. This is a good example of the function de facto having multiple signatures. The simple case is summation, the intermediate case is summation from an initial condition, and the advanced case is a custom accumulator.

The linked issue is a user using keyword-arguments for both iterable and func, which should probably be discouraged. I personally find it clearer to have 'function' throughout in the prose documentation, and I wonder if func is less clear to non-native speakers of English.

Suggested change
.. function:: accumulate(iterable, func=None, *, initial=None)
.. function:: accumulate(iterable)
accumulate(iterable, *, initial)
accumulate(iterable, func, *, initial=None)

Arguably, it should note that initial is only used if not None, too, but this is somewhat obvious from context.

A second, simpler suggestion would be as follows:

Suggested change
.. function:: accumulate(iterable, func=None, *, initial=None)
.. function:: accumulate(iterable, *, initial=None)
accumulate(iterable, func, *, initial=None)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good example of the function de facto having multiple signatures.

Yet it has one.

The linked issue is a user using keyword-arguments for both iterable and func, which should probably be discouraged.

Both argument names are part of the API.

I personally find it clearer to have 'function' throughout in the prose documentation

We can change argument name, but it looks as a compatibility break for me.

Sorry, neither suggestion is acceptable for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.. function:: accumulate(iterable, *, initial=None)
              accumulate(iterable, func, *, initial=None)

This suggestion is IMO the best because it hides the implementation detail of func=None.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"reference material should prioritize precision and completeness" (c)

Proposed changes aren't precise. Are you suggesting to change actual function signature?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I meant to hide the implementation detail. I don't think anyone is expected to do accumulate(iterable, None) (the current docs do not expose that detail for instance).

Even if the EB's decision is about "reference material should prioritize precision and completeness", it's a "SHOULD" not a "MUST", which I consider it as a recommendation and not a strict rule. When it comes at the cost of exposing implementation details, I think it's better not to.

Now, itertools.groupby explicitly documents key as being allowed to be None and says:

If not specified or is None, key defaults to an identity function and returns the element unchanged

So, if you want to keep func=None, I'd suggest stating that None defaults to addition. This would avoid two signatures in the docs and would be aligned with itertools.groupby.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which I consider it as a recommendation and not a strict rule

Given the fate of #131885 - I guess you are right :(

When it comes at the cost of exposing implementation details, I think it's better not to.

Where is the difference between implementation details and API? These "details" could be discovered anyway by standard tools for introspection.

Now function has a valid (for the inspect module) signature. Why should we lie in docs, that func=None is not accepted?

I'd suggest stating that None defaults to addition.

But that seems to be documented: "The func defaults to addition." (and default argument for func shown in the signature)


Make an iterator that returns accumulated sums or accumulated
results from other binary functions.
Expand All @@ -107,13 +107,15 @@ loops that truncate the stream.

Roughly equivalent to::

def accumulate(iterable, function=operator.add, *, initial=None):
def accumulate(iterable, func=None, *, initial=None):
'Return running totals'
# accumulate([1,2,3,4,5]) β†’ 1 3 6 10 15
# accumulate([1,2,3,4,5], initial=100) β†’ 100 101 103 106 110 115
# accumulate([1,2,3,4,5], operator.mul) β†’ 1 2 6 24 120

iterator = iter(iterable)
func = func or operator.add

total = initial
if initial is None:
try:
Expand All @@ -123,7 +125,7 @@ loops that truncate the stream.

yield total
for element in iterator:
total = function(total, element)
total = func(total, element)
yield total

To compute a running minimum, set *function* to :func:`min`.
Expand Down
Loading