This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: Fix functools.reduce code equivalent.
Type: behavior Stage: resolved
Components: Documentation, Interpreter Core Versions: Python 3.4, Python 3.5
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: docs@python, georg.brandl, pitrou, python-dev, rhettinger, serhiy.storchaka, terry.reedy
Priority: normal Keywords: patch

Created on 2014-12-14 00:27 by terry.reedy, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (6)
msg232626 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-12-14 00:27
from functools import reduce
def add(a,b): return a+b
reduce(add, {})
Traceback (most recent call last):
  File "C:\Programs\Python34\", line 3, in <module>
    reduce(add, {})
TypeError: reduce() of empty sequence with no initial value

However, the reduce-equivalent code in the doc sets a bad example and forgets to account for empty iterators.

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        value = next(it)
    else: ...

So it lets the StopIteration escape (a bad practice that can silently break iterators).  The code should be

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
            value = next(it)
        except StopIteration:
            raise TypeError("reduce() of empty sequence with no initial value") from None
    else: ...

(patch coming)
msg232634 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-12-14 09:15
I think it would be good to add Python implementation in and test they equivalence in tests.
msg232642 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-12-14 18:24
Background: the OP of #19202 proposed equivalent code for all the functool functions, including two versions for reduce. Georg combined the two versions into the one that Raymond pushed.  Both agreed that reduce was the only function that really needed this.  I called Georg's code  'excellent'.

I have changed my mind slightly because people use such code equivalents not only for understanding but also as models for writing code, and because some people have had problems when by doing the same as this model, which ignores the empty iterable case.

If you do not want to 'uglify' the doc code by making it exactly equivalent, how about qualifying the claim instead?  Change 'equivalent' to 'equivalent for non-empty iterables'.
msg232646 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-12-15 02:26
Elsewhere I have used "rough equivalent".

FWIW, the initializer defaulting to "None" is also an approximation.   It would be more technically correct to have "initializer = sentinel" where "sentinel = object()".   But of course this too would obfuscate the documentation which mainly aimed to clarify two sticky points:  1) the order of arguments to the function call (accm, x) vs (x, accm) and 2) that if an initializer isn't specified, the first value from the iterable is used.  These are the two issues that Guido found difficult to remember and caused reduce() to be banished from builtins.
msg232762 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2014-12-16 20:15
I agree with Raymond. Examples in the code are not meant to be a reference but, well, examples. That is, the educational value should come first and strict adherence to the language spec only second.

"Roughly equivalent" is already used in the functools doc, it can probably be reused :-)
msg232793 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2014-12-17 02:17
New changeset 0b3d69f15950 by Raymond Hettinger in branch '3.4':
Issue #23049:  Pure python equivalent shouldn't imply more exactitude than is really there.
Date User Action Args
2022-04-11 14:58:11adminsetgithub: 67238
2014-12-17 06:17:35berker.peksagsetstage: needs patch -> resolved
2014-12-17 02:17:55rhettingersetstatus: open -> closed
resolution: fixed
2014-12-17 02:17:32python-devsetnosy: + python-dev
messages: + msg232793
2014-12-16 20:15:39pitrousetnosy: + pitrou
messages: + msg232762
2014-12-15 02:26:35rhettingersetmessages: + msg232646
2014-12-14 18:24:06terry.reedysetkeywords: + patch
nosy: + georg.brandl
messages: + msg232642

2014-12-14 09:15:46serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg232634
2014-12-14 02:09:19rhettingersetassignee: docs@python -> rhettinger

nosy: + rhettinger
2014-12-14 00:27:27terry.reedycreate