Copy reduce() to _functools so to have functools.reduce() not raise a warning
from usage under -3.
This commit is contained in:
parent
c1b76e4aaa
commit
83e818415a
|
@ -7,8 +7,7 @@
|
|||
# Copyright (C) 2006 Python Software Foundation.
|
||||
# See C source code for _functools credits/copyright
|
||||
|
||||
from _functools import partial
|
||||
from __builtin__ import reduce
|
||||
from _functools import partial, reduce
|
||||
|
||||
# update_wrapper() and wraps() are tools to help write
|
||||
# wrapper functions that can handle naive introspection
|
||||
|
|
|
@ -267,6 +267,48 @@ class TestWraps(TestUpdateWrapper):
|
|||
self.assertEqual(wrapper.dict_attr, f.dict_attr)
|
||||
|
||||
|
||||
class TestReduce(unittest.TestCase):
|
||||
|
||||
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]
|
||||
|
||||
reduce = functools.reduce
|
||||
self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc')
|
||||
self.assertEqual(
|
||||
reduce(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], []),
|
||||
['a','c','d','w']
|
||||
)
|
||||
self.assertEqual(reduce(lambda x, y: x*y, range(2,8), 1), 5040)
|
||||
self.assertEqual(
|
||||
reduce(lambda x, y: x*y, range(2,21), 1L),
|
||||
2432902008176640000L
|
||||
)
|
||||
self.assertEqual(reduce(lambda x, y: x+y, Squares(10)), 285)
|
||||
self.assertEqual(reduce(lambda x, y: x+y, Squares(10), 0), 285)
|
||||
self.assertEqual(reduce(lambda x, y: x+y, Squares(0), 0), 0)
|
||||
self.assertRaises(TypeError, reduce)
|
||||
self.assertRaises(TypeError, reduce, 42, 42)
|
||||
self.assertRaises(TypeError, reduce, 42, 42, 42)
|
||||
self.assertEqual(reduce(42, "1"), "1") # func is never called with one item
|
||||
self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item
|
||||
self.assertRaises(TypeError, reduce, 42, (42, 42))
|
||||
|
||||
|
||||
|
||||
|
||||
def test_main(verbose=None):
|
||||
import sys
|
||||
|
@ -275,7 +317,8 @@ def test_main(verbose=None):
|
|||
TestPartialSubclass,
|
||||
TestPythonPartial,
|
||||
TestUpdateWrapper,
|
||||
TestWraps
|
||||
TestWraps,
|
||||
TestReduce,
|
||||
)
|
||||
test_support.run_unittest(*test_classes)
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Copied the implementation of reduce() to _functools.reduce() to have a
|
||||
version that did not raise a DeprecationWarning under -3.
|
||||
|
||||
- Issue #3205: When iterating over a BZ2File fails allocating memory, raise
|
||||
a MemoryError rather than silently stop the iteration.
|
||||
|
||||
|
|
|
@ -9,6 +9,84 @@
|
|||
All rights reserved.
|
||||
*/
|
||||
|
||||
/* reduce() *************************************************************/
|
||||
|
||||
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(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.");
|
||||
|
||||
|
||||
|
||||
|
||||
/* partial object **********************************************************/
|
||||
|
||||
typedef struct {
|
||||
|
@ -247,6 +325,7 @@ PyDoc_STRVAR(module_doc,
|
|||
"Tools that operate on functions.");
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"reduce", functools_reduce, METH_VARARGS, reduce_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue