Pythonic function composition
Michael J. Fromberger
Michael.J.Fromberger at Clothing.Dartmouth.EDU
Mon Oct 25 12:32:12 EDT 2004
In article <10nq3c4j3lst8e2 at corp.supernews.com>,
"Alan G Isaac" <aisaac at american.edu> wrote:
> Given a list of functions, it seems there must be a
> Pythonic approach to composition. Something like
>
> def compose(fns): return lambda x: reduce(lambda f,g: f(g),fns)(x)
>
> This will not work because the argument 'x' is not "inside".
> What is the proper formulation?
>
If you are only concerned with unary functions, then composition is
fairly trivial to deal with:
def compose(*fns):
def id(x): return x
def c2(f, g):
def h(x): return f(g(x))
return h
return reduce(c2, fns, id)
However, if you want to deal with functions that may take multiple
arguments, you must be a little more clever. Here's one way that seems
to work okay:
def compose(*fns):
def id(*args): return args
def box(res):
if isinstance(res, (list, tuple)):
return res
else:
return (res,)
def unbox(res):
if isinstance(res, (list, tuple)) and len(res) == 1:
return res[0]
else:
return res
def c2(f, g):
def h(*args):
return unbox(f(*box(g(*args))))
return h
return reduce(c2, fns, id)
For instance:
def f1(a, b):
return (a / b, a % b)
def f2(a, b):
return a + b
def f3(a):
return a + 2
h = compose(f3, f2, f1)
h(5, 3)
==> 5
This will work, but it's not the most efficient possible solution. You
could defer unboxing until the end by defining another intermediate
function.
Cheers,
-M
--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
More information about the Python-list
mailing list