如何 consume/chain 发挥 "Pythonically" 的作用?

How to consume/chain functions "Pythonically"?

我有一组函数f(x), g(x), s(x), t(x)

它们被设计为像这样链接在一起:f(g(s(t(x))))

函数的设计使其可以按任何顺序链接。我的代码的另一部分在列表中构建序列:[f, g, s, t]

有没有一种优雅的方法来获取列表并链接函数调用,得到最后结果的输出?

现在显然我可以使用一个外部类似计数器的变量来跟踪输出和一个简单的 for 循环增量索引,但我想知道是否有更 Pythonic 的方法来做到这一点?

Reduce 是完美的答案(虽然我们需要从最里面的函数开始,因此 reversed):

import functools

functions = [f, g, s, t]
y = functools.reduce(lambda a, f: f(a), reversed(functions), x)

编辑:使用常量参数,就这么简单:

p1, p2 = 5, 42
y = functools.reduce(lambda a, f: f(a, p1, p2), reversed(functions), x)

Martineau 和 Amadan 已经发布了 "elegant" 解决方案。现在真正的 pythonic 解决方案是愚蠢、简单和无聊的:

def chain(arg, *funcs):
    # chain(42, f, g, s) => f(g(s(42)))
    result = arg
    for func in reversed(funcs):
        result = func(result)
    return result

这显然不是大多数人会考虑的"elegant",但它非常明显、可读,并且非常容易跟踪和调试 - 这才是最重要的wrt/ python 的理念。

在函数式编程中,这种操作称为函数组合。 Python 标准库中没有 compose 函数,但是自己写还是很容易的:

from functools import partial
# additional import for python 3: from itertools import reduce
def compose(*args):
    return partial(reduce, lambda x, y: y(x), reversed(args))

然后你可以像这样编写函数

fgst_x = compose(f, g, s, t)(x)

funcs = [f, g, s, t]
fgst = compose(*funcs)
fgst_x = fgst(x)