Part of SF patch #1513870 (the still relevant part) -- add reduce() to
functools, and adjust docs etc.
This commit is contained in:
parent
6a2a2a0832
commit
0919a1a07b
|
@ -289,19 +289,7 @@ There are also many useful builtin functions people seem not to be
|
|||
aware of for some reason: \function{min()} and \function{max()} can
|
||||
find the minimum/maximum of any sequence with comparable semantics,
|
||||
for example, yet many people write their own
|
||||
\function{max()}/\function{min()}. Another highly useful function is
|
||||
\function{reduce()}. A classical use of \function{reduce()}
|
||||
is something like
|
||||
|
||||
\begin{verbatim}
|
||||
import sys, operator
|
||||
nums = map(float, sys.argv[1:])
|
||||
print reduce(operator.add, nums)/len(nums)
|
||||
\end{verbatim}
|
||||
|
||||
This cute little script prints the average of all numbers given on the
|
||||
command line. The \function{reduce()} adds up all the numbers, and
|
||||
the rest is just some pre- and postprocessing.
|
||||
\function{max()}/\function{min()}.
|
||||
|
||||
On the same note, note that \function{float()}, \function{int()} and
|
||||
\function{long()} all accept arguments of type string, and so are
|
||||
|
|
|
@ -836,19 +836,6 @@ class Parrot(object):
|
|||
\end{verbatim}
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{reduce}{function, sequence\optional{, initializer}}
|
||||
Apply \var{function} of two arguments cumulatively to the items of
|
||||
\var{sequence}, from left to right, so as to reduce the sequence to
|
||||
a single value. For example, \code{reduce(lambda x, y: x+y, [1, 2,
|
||||
3, 4, 5])} calculates \code{((((1+2)+3)+4)+5)}. The left argument,
|
||||
\var{x}, is the accumulated value and the right argument, \var{y},
|
||||
is the update value from the \var{sequence}. If the optional
|
||||
\var{initializer} is present, it is placed before the items of the
|
||||
sequence in the calculation, and serves as a default when the
|
||||
sequence is empty. If \var{initializer} is not given and
|
||||
\var{sequence} contains only one item, the first item is returned.
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{reload}{module}
|
||||
Reload a previously imported \var{module}. The
|
||||
argument must be a module object, so it must have been successfully
|
||||
|
@ -1058,8 +1045,6 @@ class C:
|
|||
The \var{sequence}'s items are normally numbers, and are not allowed
|
||||
to be strings. The fast, correct way to concatenate sequence of
|
||||
strings is by calling \code{''.join(\var{sequence})}.
|
||||
Note that \code{sum(range(\var{n}), \var{m})} is equivalent to
|
||||
\code{reduce(operator.add, range(\var{n}), \var{m})}
|
||||
\versionadded{2.3}
|
||||
\end{funcdesc}
|
||||
|
||||
|
|
|
@ -51,6 +51,19 @@ two:
|
|||
\end{verbatim}
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{reduce}{function, sequence\optional{, initializer}}
|
||||
Apply \var{function} of two arguments cumulatively to the items of
|
||||
\var{sequence}, from left to right, so as to reduce the sequence to
|
||||
a single value. For example, \code{reduce(lambda x, y: x+y, [1, 2,
|
||||
3, 4, 5])} calculates \code{((((1+2)+3)+4)+5)}. The left argument,
|
||||
\var{x}, is the accumulated value and the right argument, \var{y},
|
||||
is the update value from the \var{sequence}. If the optional
|
||||
\var{initializer} is present, it is placed before the items of the
|
||||
sequence in the calculation, and serves as a default when the
|
||||
sequence is empty. If \var{initializer} is not given and
|
||||
\var{sequence} contains only one item, the first item is returned.
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{update_wrapper}
|
||||
{wrapper, wrapped\optional{, assigned}\optional{, updated}}
|
||||
Update a wrapper function to look like the wrapped function. The optional
|
||||
|
|
|
@ -1893,8 +1893,8 @@ use \method{pop()} with \code{0} as the index. For example:
|
|||
|
||||
\subsection{Functional Programming Tools \label{functional}}
|
||||
|
||||
There are three built-in functions that are very useful when used with
|
||||
lists: \function{filter()}, \function{map()}, and \function{reduce()}.
|
||||
There are two built-in functions that are very useful when used with
|
||||
lists: \function{filter()} and \function{map()}.
|
||||
|
||||
\samp{filter(\var{function}, \var{sequence})} returns a sequence
|
||||
consisting of those items from the
|
||||
|
@ -1934,42 +1934,6 @@ is shorter than another). For example:
|
|||
>>> map(add, seq, seq)
|
||||
[0, 2, 4, 6, 8, 10, 12, 14]
|
||||
\end{verbatim}
|
||||
|
||||
\samp{reduce(\var{function}, \var{sequence})} returns a single value
|
||||
constructed by calling the binary function \var{function} on the first two
|
||||
items of the sequence, then on the result and the next item, and so
|
||||
on. For example, to compute the sum of the numbers 1 through 10:
|
||||
|
||||
\begin{verbatim}
|
||||
>>> def add(x,y): return x+y
|
||||
...
|
||||
>>> reduce(add, range(1, 11))
|
||||
55
|
||||
\end{verbatim}
|
||||
|
||||
If there's only one item in the sequence, its value is returned; if
|
||||
the sequence is empty, an exception is raised.
|
||||
|
||||
A third argument can be passed to indicate the starting value. In this
|
||||
case the starting value is returned for an empty sequence, and the
|
||||
function is first applied to the starting value and the first sequence
|
||||
item, then to the result and the next item, and so on. For example,
|
||||
|
||||
\begin{verbatim}
|
||||
>>> def sum(seq):
|
||||
... def add(x,y): return x+y
|
||||
... return reduce(add, seq, 0)
|
||||
...
|
||||
>>> sum(range(1, 11))
|
||||
55
|
||||
>>> sum([])
|
||||
0
|
||||
\end{verbatim}
|
||||
|
||||
Don't use this example's definition of \function{sum()}: since summing
|
||||
numbers is such a common need, a built-in function
|
||||
\code{sum(\var{sequence})} is already provided, and works exactly like
|
||||
this.
|
||||
\versionadded{2.3}
|
||||
|
||||
\subsection{List Comprehensions}
|
||||
|
@ -2739,7 +2703,7 @@ standard module \module{__builtin__}\refbimodindex{__builtin__}:
|
|||
'id', 'int', 'intern', 'isinstance', 'issubclass', 'iter',
|
||||
'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min',
|
||||
'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range',
|
||||
'reduce', 'reload', 'repr', 'reversed', 'round', 'set',
|
||||
'reload', 'repr', 'reversed', 'round', 'set',
|
||||
'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super',
|
||||
'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
|
||||
\end{verbatim}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# Copyright (C) 2006 Python Software Foundation.
|
||||
# See C source code for _functools credits/copyright
|
||||
|
||||
from _functools import partial
|
||||
from _functools import partial, reduce
|
||||
|
||||
# update_wrapper() and wraps() are tools to help write
|
||||
# wrapper functions that can handle naive introspection
|
||||
|
|
|
@ -259,6 +259,74 @@ class TestWraps(TestUpdateWrapper):
|
|||
self.assertEqual(wrapper.attr, 'This is a different test')
|
||||
self.assertEqual(wrapper.dict_attr, f.dict_attr)
|
||||
|
||||
class TestReduce(unittest.TestCase):
|
||||
func = functools.reduce
|
||||
|
||||
def test_reduce(self):
|
||||
class Squares:
|
||||
def __init__(self, max):
|
||||
self.max = max
|
||||
self.sofar = []
|
||||
|
||||
def __len__(self):
|
||||
return len(self.sofar)
|
||||
|
||||
def __getitem__(self, i):
|
||||
if not 0 <= i < self.max: raise IndexError
|
||||
n = len(self.sofar)
|
||||
while n <= i:
|
||||
self.sofar.append(n*n)
|
||||
n += 1
|
||||
return self.sofar[i]
|
||||
|
||||
self.assertEqual(self.func(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc')
|
||||
self.assertEqual(
|
||||
self.func(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], []),
|
||||
['a','c','d','w']
|
||||
)
|
||||
self.assertEqual(self.func(lambda x, y: x*y, range(2,8), 1), 5040)
|
||||
self.assertEqual(
|
||||
self.func(lambda x, y: x*y, range(2,21), 1L),
|
||||
2432902008176640000L
|
||||
)
|
||||
self.assertEqual(self.func(lambda x, y: x+y, Squares(10)), 285)
|
||||
self.assertEqual(self.func(lambda x, y: x+y, Squares(10), 0), 285)
|
||||
self.assertEqual(self.func(lambda x, y: x+y, Squares(0), 0), 0)
|
||||
self.assertRaises(TypeError, self.func)
|
||||
self.assertRaises(TypeError, self.func, 42, 42)
|
||||
self.assertRaises(TypeError, self.func, 42, 42, 42)
|
||||
self.assertEqual(self.func(42, "1"), "1") # func is never called with one item
|
||||
self.assertEqual(self.func(42, "", "1"), "1") # func is never called with one item
|
||||
self.assertRaises(TypeError, self.func, 42, (42, 42))
|
||||
|
||||
class BadSeq:
|
||||
def __getitem__(self, index):
|
||||
raise ValueError
|
||||
self.assertRaises(ValueError, self.func, 42, BadSeq())
|
||||
|
||||
# Test reduce()'s use of iterators.
|
||||
def test_iterator_usage(self):
|
||||
class SequenceClass:
|
||||
def __init__(self, n):
|
||||
self.n = n
|
||||
def __getitem__(self, i):
|
||||
if 0 <= i < self.n:
|
||||
return i
|
||||
else:
|
||||
raise IndexError
|
||||
|
||||
from operator import add
|
||||
self.assertEqual(self.func(add, SequenceClass(5)), 10)
|
||||
self.assertEqual(self.func(add, SequenceClass(5), 42), 52)
|
||||
self.assertRaises(TypeError, self.func, add, SequenceClass(0))
|
||||
self.assertEqual(self.func(add, SequenceClass(0), 42), 42)
|
||||
self.assertEqual(self.func(add, SequenceClass(1)), 0)
|
||||
self.assertEqual(self.func(add, SequenceClass(1), 42), 42)
|
||||
|
||||
d = {"one": 1, "two": 2, "three": 3}
|
||||
self.assertEqual(self.func(add, d), "".join(d.keys()))
|
||||
|
||||
|
||||
|
||||
|
||||
def test_main(verbose=None):
|
||||
|
@ -268,7 +336,8 @@ def test_main(verbose=None):
|
|||
TestPartialSubclass,
|
||||
TestPythonPartial,
|
||||
TestUpdateWrapper,
|
||||
TestWraps
|
||||
TestWraps,
|
||||
TestReduce
|
||||
)
|
||||
test_support.run_unittest(*test_classes)
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ endif
|
|||
|
||||
if exists("python_highlight_builtins")
|
||||
syn keyword pythonBuiltin unichr all set abs vars int __import__ unicode
|
||||
syn keyword pythonBuiltin enumerate reduce exit issubclass
|
||||
syn keyword pythonBuiltin enumerate exit issubclass
|
||||
syn keyword pythonBuiltin divmod file Ellipsis isinstance open any
|
||||
syn keyword pythonBuiltin locals help filter basestring slice copyright min
|
||||
syn keyword pythonBuiltin super sum tuple hex execfile long id chr
|
||||
|
|
|
@ -901,7 +901,7 @@ lambda [param_list]: returnedExpr
|
|||
-- Creates an anonymous function. returnedExpr must be
|
||||
an expression, not a statement (e.g., not "if xx:...",
|
||||
"print xxx", etc.) and thus can't contain newlines.
|
||||
Used mostly for filter(), map(), reduce() functions, and GUI callbacks..
|
||||
Used mostly for filter(), map() functions, and GUI callbacks..
|
||||
List comprehensions
|
||||
result = [expression for item1 in sequence1 [if condition1]
|
||||
[for item2 in sequence2 ... for itemN in sequenceN]
|
||||
|
@ -1005,11 +1005,6 @@ property() Created a property with access controlled by functions.
|
|||
range(start [,end Returns list of ints from >= start and < end.With 1 arg,
|
||||
[, step]]) list from 0..arg-1With 2 args, list from start..end-1With 3
|
||||
args, list from start up to end by step
|
||||
reduce(f, list [, Applies the binary function f to the items oflist so as to
|
||||
init]) reduce the list to a single value.If init given, it is
|
||||
"prepended" to list.
|
||||
Re-parses and re-initializes an already imported module.
|
||||
Useful in interactive mode, if you want to reload amodule
|
||||
reload(module) after fixing it. If module was syntacticallycorrect but had
|
||||
an error in initialization, mustimport it one more time
|
||||
before calling reload().
|
||||
|
|
|
@ -386,7 +386,7 @@ support for features needed by `python-mode'.")
|
|||
"isinstance" "issubclass" "iter" "len" "license"
|
||||
"list" "locals" "long" "map" "max" "min" "object"
|
||||
"oct" "open" "ord" "pow" "property" "range"
|
||||
"reduce" "reload" "repr" "round"
|
||||
"reload" "repr" "round"
|
||||
"setattr" "slice" "staticmethod" "str" "sum"
|
||||
"super" "tuple" "type" "unichr" "unicode" "vars"
|
||||
"zip")
|
||||
|
|
|
@ -242,12 +242,88 @@ static PyTypeObject partial_type = {
|
|||
};
|
||||
|
||||
|
||||
/* reduce (used to be a builtin) ********************************************/
|
||||
|
||||
static PyObject *
|
||||
functools_reduce(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *seq, *func, *result = NULL, *it;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
|
||||
return NULL;
|
||||
if (result != NULL)
|
||||
Py_INCREF(result);
|
||||
|
||||
it = PyObject_GetIter(seq);
|
||||
if (it == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"reduce() arg 2 must support iteration");
|
||||
Py_XDECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((args = PyTuple_New(2)) == NULL)
|
||||
goto Fail;
|
||||
|
||||
for (;;) {
|
||||
PyObject *op2;
|
||||
|
||||
if (args->ob_refcnt > 1) {
|
||||
Py_DECREF(args);
|
||||
if ((args = PyTuple_New(2)) == NULL)
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
op2 = PyIter_Next(it);
|
||||
if (op2 == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto Fail;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == NULL)
|
||||
result = op2;
|
||||
else {
|
||||
PyTuple_SetItem(args, 0, result);
|
||||
PyTuple_SetItem(args, 1, op2);
|
||||
if ((result = PyEval_CallObject(func, args)) == NULL)
|
||||
goto Fail;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(args);
|
||||
|
||||
if (result == NULL)
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"reduce() of empty sequence with no initial value");
|
||||
|
||||
Py_DECREF(it);
|
||||
return result;
|
||||
|
||||
Fail:
|
||||
Py_XDECREF(args);
|
||||
Py_XDECREF(result);
|
||||
Py_DECREF(it);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(functools_reduce_doc,
|
||||
"reduce(function, sequence[, initial]) -> value\n\
|
||||
\n\
|
||||
Apply a function of two arguments cumulatively to the items of a sequence,\n\
|
||||
from left to right, so as to reduce the sequence to a single value.\n\
|
||||
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
|
||||
((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
|
||||
of the sequence in the calculation, and serves as a default when the\n\
|
||||
sequence is empty.");
|
||||
|
||||
/* module level code ********************************************************/
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Tools that operate on functions.");
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -3012,7 +3012,7 @@ init_ast(void)
|
|||
if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;
|
||||
if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
|
||||
return;
|
||||
if (PyModule_AddStringConstant(m, "__version__", "45597") < 0)
|
||||
if (PyModule_AddStringConstant(m, "__version__", "51600") < 0)
|
||||
return;
|
||||
if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return;
|
||||
if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0)
|
||||
|
|
Loading…
Reference in New Issue