使用 reduce 遍历函数列表并调用每个函数
Using reduce to iterate over list of functions and call each one
目前我正在使用带有函数名称的字符串列表来修复我的软件流程:
flow = [
"func1",
"func2",
"func3",
"func4",
"func5"
]
然后我遍历流程并调用每一个传递选项:
options = {}
[getattr(__import__(phase), phase)(options) for phase in flow]
我想知道是否可以使用 reduce 来避免副作用。目前,这种方法使函数接收选项,但不需要 return 下一个函数的选项,所以我正在更改在其他范围内声明的选项。
谢谢。
您可以使用 functools.reduce
(在其他函数式编程语言中有时称为 fold
,例如 Haskell)来真正调用该函数。
然而,在那种情况下,您需要定义一个函数采用 两个参数:旧累加器 值和元素本身。您只需忽略旧值并在元素上调用函数。
因此对于通用函数 f(x)
,您可以使用:
functools.reduce(lambda _,x:f(x),list,initializer=0)
所以在你的情况下是:
options = {}
functools.reduce(lambda _,phase:getattr(__import__(phase),phase)(options),flow,initializer=0)
编辑:
在重读你的问题后,在我看来,每个函数都将 options
作为输入,并生成应该传递给下一个函数的 "new" 选项。那么第一个函数的return,就是下一个函数的lambda
的第一个参数。所以你可以像这样把它折叠起来:
first_options = {}
functools.reduce(lambda options,phase:getattr(__import__(phase),phase)(options),flow,initializer=first_options)
这将导致等同于:
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
但这当然发生在内部reduce
。
所以 reduce 接受一个函数,比如 reduce_func
,接受 2 个参数。当它遍历一个列表时,它将前两项作为第一次调用的 reduce_func
的参数,然后在每次后续调用中,使用 return 值作为第一个参数,下一个值列表作为第二个参数。这意味着,对您来说,reduce_func
需要如下
def reduce_func(param, f):
return f(param)
您的列表必须如下所示:
[options, func1, func2, func3, func4]
现在,我用的是函数列表,没有用import。代替 f
,您可以将 [module].[function]
作为字符串传入(将参数称为 func_str
),并在 reduce_func
内部进行一些拆分和一些设置.
目前我正在使用带有函数名称的字符串列表来修复我的软件流程:
flow = [
"func1",
"func2",
"func3",
"func4",
"func5"
]
然后我遍历流程并调用每一个传递选项:
options = {}
[getattr(__import__(phase), phase)(options) for phase in flow]
我想知道是否可以使用 reduce 来避免副作用。目前,这种方法使函数接收选项,但不需要 return 下一个函数的选项,所以我正在更改在其他范围内声明的选项。
谢谢。
您可以使用 functools.reduce
(在其他函数式编程语言中有时称为 fold
,例如 Haskell)来真正调用该函数。
然而,在那种情况下,您需要定义一个函数采用 两个参数:旧累加器 值和元素本身。您只需忽略旧值并在元素上调用函数。
因此对于通用函数 f(x)
,您可以使用:
functools.reduce(lambda _,x:f(x),list,initializer=0)
所以在你的情况下是:
options = {}
functools.reduce(lambda _,phase:getattr(__import__(phase),phase)(options),flow,initializer=0)
编辑:
在重读你的问题后,在我看来,每个函数都将 options
作为输入,并生成应该传递给下一个函数的 "new" 选项。那么第一个函数的return,就是下一个函数的lambda
的第一个参数。所以你可以像这样把它折叠起来:
first_options = {}
functools.reduce(lambda options,phase:getattr(__import__(phase),phase)(options),flow,initializer=first_options)
这将导致等同于:
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
但这当然发生在内部reduce
。
所以 reduce 接受一个函数,比如 reduce_func
,接受 2 个参数。当它遍历一个列表时,它将前两项作为第一次调用的 reduce_func
的参数,然后在每次后续调用中,使用 return 值作为第一个参数,下一个值列表作为第二个参数。这意味着,对您来说,reduce_func
需要如下
def reduce_func(param, f):
return f(param)
您的列表必须如下所示:
[options, func1, func2, func3, func4]
现在,我用的是函数列表,没有用import。代替 f
,您可以将 [module].[function]
作为字符串传入(将参数称为 func_str
),并在 reduce_func
内部进行一些拆分和一些设置.