Generalize reduce() to work with iterators.
NEEDS DOC CHANGES.
diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py
index 66f40c1..5584587 100644
--- a/Lib/test/test_iter.py
+++ b/Lib/test/test_iter.py
@@ -385,4 +385,17 @@
             except OSError:
                 pass
 
+    # Test reduces()'s use of iterators.
+    def test_builtin_reduce(self):
+        from operator import add
+        self.assertEqual(reduce(add, SequenceClass(5)), 10)
+        self.assertEqual(reduce(add, SequenceClass(5), 42), 52)
+        self.assertRaises(TypeError, reduce, add, SequenceClass(0))
+        self.assertEqual(reduce(add, SequenceClass(0), 42), 42)
+        self.assertEqual(reduce(add, SequenceClass(1)), 0)
+        self.assertEqual(reduce(add, SequenceClass(1), 42), 42)
+
+        d = {"one": 1, "two": 2, "three": 3}
+        self.assertEqual(reduce(add, d), "".join(d.keys()))
+
 run_unittest(TestCase)
diff --git a/Misc/NEWS b/Misc/NEWS
index 617146c..d707a7a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,6 +22,7 @@
     map()
     max()
     min()
+    reduce()
 
 
 What's New in Python 2.1 (final)?
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 0c20d10..5209607 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1851,26 +1851,25 @@
 static PyObject *
 builtin_reduce(PyObject *self, PyObject *args)
 {
-	PyObject *seq, *func, *result = NULL;
-	PySequenceMethods *sqf;
-	register int i;
+	PyObject *seq, *func, *result = NULL, *it;
 
 	if (!PyArg_ParseTuple(args, "OO|O:reduce", &func, &seq, &result))
 		return NULL;
 	if (result != NULL)
 		Py_INCREF(result);
 
-	sqf = seq->ob_type->tp_as_sequence;
-	if (sqf == NULL || sqf->sq_item == NULL) {
+	it = PyObject_GetIter(seq);
+	if (it == NULL) {
 		PyErr_SetString(PyExc_TypeError,
-		    "reduce() arg 2 must be a sequence");
+		    "reduce() arg 2 must support iteration");
+		Py_XDECREF(result);
 		return NULL;
 	}
 
 	if ((args = PyTuple_New(2)) == NULL)
 		goto Fail;
 
-	for (i = 0; ; ++i) {
+	for (;;) {
 		PyObject *op2;
 
 		if (args->ob_refcnt > 1) {
@@ -1879,12 +1878,18 @@
 				goto Fail;
 		}
 
-		if ((op2 = (*sqf->sq_item)(seq, i)) == NULL) {
-			if (PyErr_ExceptionMatches(PyExc_IndexError)) {
-				PyErr_Clear();
-				break;
+		op2 = PyIter_Next(it);
+		if (op2 == NULL) {
+			/* StopIteration is *implied* by a NULL return from
+			 * PyIter_Next() if PyErr_Occurred() is false.
+			 */
+			if (PyErr_Occurred()) {
+				if (PyErr_ExceptionMatches(PyExc_StopIteration))
+					PyErr_Clear();
+				else
+					goto Fail;
 			}
-			goto Fail;
+			break;
 		}
 
 		if (result == NULL)
@@ -1903,11 +1908,13 @@
 		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;
 }