Index: Python/bltinmodule.c =================================================================== --- Python/bltinmodule.c (revision 57913) +++ Python/bltinmodule.c (working copy) @@ -2094,7 +2094,59 @@ of parameter 'start' (which defaults to 0). When the sequence is\n\ empty, returns start."); +static PyObject* +builtin_product(PyObject *self, PyObject *args) +{ + PyObject *seq; + PyObject *result = NULL; + PyObject *temp, *item, *iter; + if (!PyArg_UnpackTuple(args, "product", 1, 2, &seq, &result)) + return NULL; + + iter = PyObject_GetIter(seq); + if (iter == NULL) + return NULL; + + if (result == NULL) { + result = PyInt_FromLong(1); + if (result == NULL) { + Py_DECREF(iter); + return NULL; + } + } else { + Py_INCREF(result); + } + + for(;;) { + item = PyIter_Next(iter); + if (item == NULL) { + /* error, or end-of-sequence */ + if (PyErr_Occurred()) { + Py_DECREF(result); + result = NULL; + } + break; + } + temp = PyNumber_Multiply(result, item); + Py_DECREF(result); + Py_DECREF(item); + result = temp; + if (result == NULL) + break; + } + Py_DECREF(iter); + return result; +} + +PyDoc_STRVAR(product_doc, +"product(sequence[, start]) -> value\n\ +\n\ +Returns the product of a sequence of numbers times the value\n\ +of parameter 'start' (which defaults to 1). When the sequence is\n\ +empty, returns start."); + + static PyObject * builtin_isinstance(PyObject *self, PyObject *args) { @@ -2296,6 +2348,7 @@ {"open", (PyCFunction)builtin_open, METH_VARARGS | METH_KEYWORDS, open_doc}, {"ord", builtin_ord, METH_O, ord_doc}, {"pow", builtin_pow, METH_VARARGS, pow_doc}, + {"product", builtin_product, METH_VARARGS, product_doc}, {"range", builtin_range, METH_VARARGS, range_doc}, {"raw_input", builtin_raw_input, METH_VARARGS, raw_input_doc}, {"reduce", builtin_reduce, METH_VARARGS, reduce_doc}, Index: Doc/library/functions.rst =================================================================== --- Doc/library/functions.rst (revision 57913) +++ Doc/library/functions.rst (working copy) @@ -1104,7 +1104,15 @@ .. versionadded:: 2.3 +.. function:: product(iterable[, start]) + Multiplies *start* and the items of an *iterable* from left to right and + returns the product. *start* defaults to ``1``. The *iterable*'s items are + normally numbers. Note that ``product(range(n), m)`` is equivalent to + ``reduce(operator.mul, range(n), m)`` + .. versionadded:: 2.6 + + .. function:: super(type[, object-or-type]) Return the superclass of *type*. If the second argument is omitted the super Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 57913) +++ Lib/test/test_builtin.py (working copy) @@ -1697,6 +1697,19 @@ raise ValueError self.assertRaises(ValueError, sum, BadSeq()) + def test_product(self): + self.assertEqual(product([]), 1) + self.assertEqual(product(range(2,8)), 5040) + self.assertEqual(product(iter(range(2,8))), 5040) + + self.assertRaises(TypeError, product) + self.assertRaises(TypeError, product, 42) + self.assertRaises(TypeError, product, ['a', 'b', 'c']) + self.assertRaises(TypeError, product, ['a', 'b', 'c'], '') + self.assertRaises(TypeError, product, [[1], [2], [3]]) + self.assertRaises(TypeError, product, [{2:3}]) + self.assertRaises(TypeError, product, [{2:3}]*2, {2:3}) + def test_tuple(self): self.assertEqual(tuple(()), ()) t0_3 = (0, 1, 2, 3)