473,398 Members | 2,125 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,398 software developers and data experts.

Pythonic function composition

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?

Thanks,
Alan Isaac
Jul 18 '05 #1
6 3351
Alan G Isaac 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?


You need to pass a function that makes a function (a "factory") to reduce():
fns = [lambda x: x+2, lambda x: x*2, lambda x: x*x]
def compose(f, g): .... def fog(x):
.... return f(g(x))
.... return fog
.... g1 = reduce(compose, fns)
g1(2) 10

The same with lambdas:
g2 = reduce(lambda f, g: lambda x: f(g(x)), fns)
g2(2)

10

Peter

Jul 18 '05 #2
Alan G Isaac <ai****@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?


There are probably several ways to do it.
The following is the one which come to my mind first.

The trick is to first define a function that composes
two functions, and then use reduce() to apply it to an
arbitrary number of functions.
def compose2 (f, g): .... def h (x):
.... return f(g(x))
.... return h
.... def compose (fns): .... return reduce(compose2, fns)
....

Some testing:
def add42 (x): return x + 42 .... def mul2 (x): return x * 2 .... def sub5 (x): return x - 5 .... def div3 (x): return x / 3 .... a = compose((add42, mul2, sub5, div3))
a(1)

27

There's no need to juggle with lambda in this case.
Lambda has its uses, but this isn't one of them.

Best regards
Oliver

--
Oliver Fromme, Konrad-Celtis-Str. 72, 81369 Munich, Germany

``All that we see or seem is just a dream within a dream.''
(E. A. Poe)
Jul 18 '05 #3

"Peter Otten" <__*******@web.de> wrote in message
news:cl************@news.t-online.com...
g2 = reduce(lambda f, g: lambda x: f(g(x)), fns)

Cool. That gets me there. I think
def compose(fns) : return reduce(lambda f, g: lambda x: f(g(x)), fns)
does exactly what I want.

Thanks,
Alan Isaac

Jul 18 '05 #4
"Oliver Fromme" <ol**@haluter.fromme.com> wrote in message
news:2u*************@uni-berlin.de...
There's no need to juggle with lambda in this case.
Lambda has its uses, but this isn't one of them.


I kind of like the lambda version (see Peter's post).
But maybe it is more opaque.

Thanks,
Alan
Jul 18 '05 #5
In article <10*************@corp.supernews.com>,
"Alan G Isaac" <ai****@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
Jul 18 '05 #6
How about some recursion?

def compose(f, *fns):
if not fns:
return f
else:
return lambda x: f(compose(*fns)(x))

....
from math import *
foo = compose(sin, sqrt, abs) # sin(sqrt(abs(x)))
foo(-((pi/2.)**2))

1.0

....or you could try it this way, which makes some assumptions about
function names, but will possibly run faster:

def compose(*fns):
fnames = [f.__name__ for f in fns]
expr = "%s(x%s" % ('('.join(fnames),')'*len(fns))
return eval("lambda x: %s" % expr)
Jul 18 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Charles Krug | last post by:
I've a function that needs to maintain an ordered sequence between calls. In C or C++, I'd declare the pointer (or collection object) static at the function scope. What's the Pythonic way to...
8
by: Gert Van den Eynde | last post by:
Hi all, I have a question on interface design: I have a set of objects that are interlinked in the real world: object of class A needs for example for the operator() an object of class B. On...
4
by: Frederik Vanderhaegen | last post by:
Hi, Can anyone explain me the difference between aggregation and composition? I know that they both are "whole-part" relationships and that composition parts are destroyed when the composition...
3
by: David MacKay | last post by:
Dear Greater Py, <motivation note="reading this bit is optional"> I am writing a command-line reader for python. I'm trying to write something with the same brevity as perl's one-liner ...
4
by: Carl J. Van Arsdall | last post by:
It seems the more I come to learn about Python as a langauge and the way its used I've come across several discussions where people discuss how to do things using an OO model and then how to design...
8
by: Simon Willison | last post by:
Hi all, I have an API design question. I'm writing a function that can either succeed or fail. Most of the time the code calling the function won't care about the reason for the failure, but...
5
by: StephQ | last post by:
This is from a thread that I posted on another forum some days ago. I didn't get any response, so I'm proposing it in this ng in hope of better luck :) The standard explanation is that pointer...
26
by: Frank Samuelson | last post by:
I love Python, and it is one of my 2 favorite languages. I would suggest that Python steal some aspects of the S language. ------------------------------------------------------- 1. Currently...
4
by: Kay Schluehr | last post by:
As you know, there is no operator for function composition in Python. When you have two functions F and G and want to express the composition F o G you have to create a new closure lambda...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.