使用 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 内部进行一些拆分和一些设置.