Reputation:
Currently i'm using a list of strings with names of functions to fix the flow of my software:
flow = [
"func1",
"func2",
"func3",
"func4",
"func5"
]
Then i iterate over the flow and call each one passing the options:
options = {}
[getattr(__import__(phase), phase)(options) for phase in flow]
I would like to know if is it possible to do the same, but avoiding side effects, using reduce. Currently, this approach it's making the functions receive the option, but isn't necessary return the options for the next function, so i'm changing the options that is declared in other scope.
Thanks.
Upvotes: 2
Views: 2178
Reputation: 323
so reduce takes one a function, say reduce_func
, that takes on 2 arguments. When it goes through a list it takes the first two items as the params of reduce_func
for the first call, then on each subsequent call, uses the return value as the first param, and the next value on the list as the second param. This means, for you, reduce_func
needs to be the following
def reduce_func(param, f):
return f(param)
and your list needs to be the following:
[options, func1, func2, func3, func4]
Now, I used a list of functions and didn't use import. In stead of f
, you could pass in [module].[function]
as a string (call the param something like func_str
), and do some splitting and inside of reduce_func
as some set up.
Upvotes: 0
Reputation: 476584
You can use functools.reduce
(which is sometimes called fold
in other functional programming languages like Haskell) to indeed call the function.
In that case however you will need to define a function taking two parameters: the old accumulator value and the element itself. You simply ignore the old value and call the function on the element.
So for a generic function f(x)
, you can do this with:
functools.reduce(lambda _,x:f(x),list,initializer=0)
So in your case that would be:
options = {}
functools.reduce(lambda _,phase:getattr(__import__(phase),phase)(options),flow,initializer=0)
EDIT:
after rereading your question, it appears to me that each of the functions takes as input options
, and generates the "new" options that should be passed to the next function. Well the return of the first function, is the first parameter of the lambda
of the next function. So you can fold it together like:
first_options = {}
functools.reduce(lambda options,phase:getattr(__import__(phase),phase)(options),flow,initializer=first_options)
This will result in something equivalent to:
options_0 = first_options
options_1 = getattr(__import__(phase),flow[0])(options_0)
options_2 = getattr(__import__(phase),flow[1])(options_1)
# ...
return options_n
but of course this happens inside the reduce
.
Upvotes: 2