Part of SF patch #1513870 (the still relevant part) -- add reduce() to
functools, and adjust docs etc.
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 7b23210..1b363fc 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -242,12 +242,88 @@
 };
 
 
+/* 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 */
 };