Index: Doc/lib/libfunctools.tex =================================================================== --- Doc/lib/libfunctools.tex (revision 53779) +++ Doc/lib/libfunctools.tex (working copy) @@ -17,8 +17,15 @@ be treated as a function for the purposes of this module. -The \module{functools} module defines the following function: +The \module{functools} module defines the following functions: +\begin{funcdesc}{compose}{*functions} +Returns a new function such that \code{compose(a,b,c)(arg1, arg2, arg3)} +is equivalent to \code{a(b(c(arg1, arg2, arg3)))} + +\versionadded{2.6} +\end{funcdesc} + \begin{funcdesc}{partial}{func\optional{,*args}\optional{, **keywords}} Return a new \class{partial} object which when called will behave like \var{func} called with the positional arguments \var{args} and keyword Index: Lib/test/test_functools.py =================================================================== --- Lib/test/test_functools.py (revision 53779) +++ Lib/test/test_functools.py (working copy) @@ -267,7 +267,36 @@ self.assertEqual(wrapper.dict_attr, f.dict_attr) +class TestCompose(unittest.TestCase): + def test_single_value(self): + def a(v): + return v*v + def b(v): + return v+2 + c = functools.compose(a,b) + self.assertEqual(c(5), 49) + c = functools.compose(b,a) + self.assertEqual(c(5), 27) + + def test_multiple_values(self): + def a(v): + return v+2 + def b(x,y): + return x*y + c = functools.compose(a,b) + self.assertEqual(c(5,6), 32) + + def test_keyword_values(self): + def a(v): + return v+2 + def b(x,y): + return x + c = functools.compose(a,b) + self.assertEqual(c(y=5,x=6), 8) + self.assertEqual(c(x=5,y=6), 7) + + def test_main(verbose=None): import sys test_classes = ( @@ -275,7 +304,8 @@ TestPartialSubclass, TestPythonPartial, TestUpdateWrapper, - TestWraps + TestWraps, + TestCompose ) test_support.run_unittest(*test_classes) Index: Lib/functools.py =================================================================== --- Lib/functools.py (revision 53779) +++ Lib/functools.py (working copy) @@ -49,3 +49,14 @@ """ return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) + +def compose(*funcs): + """Returns a function such that compose(a,b,c)(arg1, arg2, arg3) + is equivalent to a(b(c(arg1, arg2, arg3))).""" + def _composefunc(*args, **kw): + l = reversed(funcs) + rv = l.next()(*args, **kw) + for f in l: + rv = f(rv) + return rv + return _composefunc