I am reading Joseph Howse OpenCV book. In the appendix, he's discussing creation of composite function from 2 other functions, as follows:
def createCompositeFunction(func1, func2):
return lambda x : func2(func1(x))
How could I write this for an arbitrary number of functions, like so
def createCompositeFunction(*funcs):
pass
I assume this should be done using recursion, but I can not wrap my head around it. Any suggestions?
CodePudding user response:
You don't need recursion; this is a simple iterative problem:
def createCompositeFunction(*funcs):
def apply(x):
for func in funcs:
x = func(x)
return x
return apply
def f1(x):
return x 2
def f2(x):
return x * 3
def f3(x):
return x / 2
comp = createCompositeFunction(f1, f2, f3)
print("comp(1) =", comp(1))
print("comp(2) =", comp(2))
Running the above code will output:
comp(1) = 4.5
comp(2) = 6.0
CodePudding user response:
You can use accumulate
from functools
(and keep intermediate results):
from itertools import accumulate
def f1(x): return x 2
def f2(x): return x * 3
def f3(x): return x / 4
def createCompositeFunction(func1, func2):
return lambda x: func2(func1(x))
# For x=3
l = [f(3) for f in accumulate([f1, f2, f3], createCompositeFunction)]
Output:
>>> l
[5, 15, 3.75] # <- the last item l[-1] is the final value
CodePudding user response:
@larsks has a pretty nice answer. If you're interested in recursion specifically, here's an option:
def createCompositeFunction(*funcs):
func = funcs[0]
funcs = funcs[1:]
if len(funcs) == 0:
return func
return lambda x: func(createCompositeFunction(*funcs)(x))
def square(x):
return x ** 2
square_thrice = createCompositeFunction(square, square, square)
print(square_thrice(2))
Output:
>>> 256
CodePudding user response:
What you're asking for in functional programming terms is a reducer higher-order function. Python provides functools.reduce
to this end:
def reduce(function, iterable, initializer=None):
Where function
should be an applicator, iterable
is the chain of funcs you want to apply, and initializer
is your argument.
Here's a simple example on one argument:
from functools import reduce
def sub1(a):
return a - 1
def mul2(a):
return a * 2
def apply(x, f):
return f(x)
def compose(*fns):
return lambda x: reduce(apply, fns, x)
print(compose(sub1, mul2)(4)) # => 6
You can partial or lambda
in extra args as needed:
from functools import partial, reduce
from operator import mul, sub
def compose(*fns):
return lambda x: reduce(lambda x, f: f(x), fns, x)
print(compose(lambda x: sub(x, 2), partial(mul, 3))(4)) # => 6
There are a lot of ways to go with this sort of thing, so I'll leave it at this absent further information about your use case.
As it turns out, this is pretty much a more fleshed-out version of Compute a chain of functions in python.