]> granicus.if.org Git - python/commitdiff
Copy reduce() to _functools so to have functools.reduce() not raise a warning
authorBrett Cannon <bcannon@gmail.com>
Sat, 9 Aug 2008 23:30:55 +0000 (23:30 +0000)
committerBrett Cannon <bcannon@gmail.com>
Sat, 9 Aug 2008 23:30:55 +0000 (23:30 +0000)
from usage under -3.

Lib/functools.py
Lib/test/test_functools.py
Misc/NEWS
Modules/_functoolsmodule.c

index 30e1d24fd2849269789cf76c6c9855949c4a99ad..a54f03083231379c642f7d6e0bc65e391f07bbd8 100644 (file)
@@ -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
index 6012f9f8551803eb4ef7c3c2716c70f51974b457..30d419da21d32db3acda8c81df8823454e30832f 100644 (file)
@@ -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)
 
index 582bd22c5639e0de9b072cab00fd3fb9b139cbfb..60a783db54e7550826e9f644ad300769d73a4c8e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index 32b246b07a3ed56e8ba93ce9fe9988be9a102285..5dfbc15c139eea1a7eb917ef86d7883a001b116b 100644 (file)
@@ -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 */
 };