Index: Doc/lib/libitertools.tex =================================================================== --- Doc/lib/libitertools.tex (revision 47103) +++ Doc/lib/libitertools.tex (working copy) @@ -323,10 +323,14 @@ \begin{funcdesc}{starmap}{function, iterable} Make an iterator that computes the function using arguments tuples obtained from the iterable. Used instead of \function{imap()} when - argument parameters are already grouped in tuples from a single iterable + argument parameters are already grouped in iterables from a single iterable (the data has been ``pre-zipped''). The difference between \function{imap()} and \function{starmap()} parallels the distinction between \code{function(a,b)} and \code{function(*c)}. + + Note that the iterable is not restricted to returning tuples; any kind of + iterable that can be *-expanded is acceptable. + Equivalent to: \begin{verbatim} Index: Lib/test/test_itertools.py =================================================================== --- Lib/test/test_itertools.py (revision 47103) +++ Lib/test/test_itertools.py (working copy) @@ -234,12 +234,17 @@ self.assertEqual(take(3, starmap(operator.pow, izip(count(), count(1)))), [0**1, 1**2, 2**3]) self.assertEqual(list(starmap(operator.pow, [])), []) - self.assertRaises(TypeError, list, starmap(operator.pow, [[4,5]])) self.assertRaises(TypeError, starmap) self.assertRaises(TypeError, starmap, operator.pow, [(4,5)], 'extra') self.assertRaises(TypeError, starmap(10, [(4,5)]).next) self.assertRaises(ValueError, starmap(errfunc, [(4,5)]).next) self.assertRaises(TypeError, starmap(onearg, [(4,5)]).next) + + def gen(): + yield {1: 'a', 2: 'b'} + yield {3: 'a', 4: 'b'} + + self.assertEqual(list(starmap(operator.add, gen())), [3, 7]) def test_islice(self): for args in [ # islice(args) should agree with range(args) Index: Modules/itertoolsmodule.c =================================================================== --- Modules/itertoolsmodule.c (revision 47103) +++ Modules/itertoolsmodule.c (working copy) @@ -1346,6 +1346,7 @@ starmap_next(starmapobject *lz) { PyObject *args; + PyObject *tup_args; PyObject *result; PyObject *it = lz->it; @@ -1353,14 +1354,14 @@ args = (*it->ob_type->tp_iternext)(it); if (args == NULL) return NULL; - if (!PyTuple_CheckExact(args)) { - Py_DECREF(args); - PyErr_SetString(PyExc_TypeError, - "iterator must return a tuple"); - return NULL; - } - result = PyObject_Call(lz->func, args, NULL); - Py_DECREF(args); + + tup_args = PySequence_Tuple(args); + Py_DECREF(args); + if (NULL == tup_args) + return NULL; + + result = PyObject_Call(lz->func, tup_args, NULL); + Py_DECREF(tup_args); return result; }