问题 Python中更好的函数组合


我在Python工作。最近,我发现了一个很棒的小包 FN。我一直在用它来进行功能组合。

例如,而不是:

baz(bar(foo(x))))

用fn,你可以写:

(F() >> foo >> bar >> baz)(x) .

当我看到这个时,我立刻想到了Clojure:

(-> x foo bar baz) .

但请注意,在Clojure中,输入位于左侧。我想知道这在python / fn中是否可行。


3318
2018-06-23 19:22


起源

虽然运算符重载行为很有意思,但对我而言,这在实际代码中似乎是件坏事。 - Markus Unterwaditzer
如果这就是你所要求的,那么就无法在Python中使用那种确切的语法。您可以通过各种方式对其进行近似。你在语法方面究竟有什么重要的? - BrenBarn
保持流动从左到右。目前,组合函数的论证是最后的。如果我能写F()>> x >> foo >> bar >> baz或类似的话会更清楚。 - Charles R


答案:


你不能复制确切的语法,但你可以做类似的事情:

def f(*args):
    result = args[0]

    for func in args[1:]:
        result = func(result)

    return result

似乎工作:

>>> f('a test', reversed, sorted, ''.join)
' aestt'

10
2018-06-23 19:31





你不能得到那种确切的语法,尽管你可以得到类似的东西 F(x)(foo, bar, baz)。这是一个简单的例子:

class F(object):
    def __init__(self, arg):
        self.arg = arg

    def __call__(self, *funcs):
        arg = self.arg
        for f in funcs:
            arg = f(arg)
        return arg

def a(x):
    return x+2
def b(x):
    return x**2
def c(x):
    return 3*x

>>> F(2)(a, b, c)
48
>>> F(2)(c, b, a)
38

这与Blender的答案略有不同,因为它存储了参数,以后可以在不同的函数中重复使用。

这有点像普通函数应用程序的反面:不是预先指定函数并留下一些稍后要指定的参数,而是指定参数并保留稍后指定的函数。这是一个有趣的玩具,但很难想到为什么你真的想要这个。


2
2018-06-23 19:34





如果你想使用 fn,有点hack你可以更接近Clojure语法:

>>> def r(x): return lambda: x
>>> (F() >> r(x) >> foo >> bar >> baz)()

看看我如何在组合链的开头添加另一个函数,它将返回 x 什么时候叫。这个问题是你仍然需要调用你的组合函数,只是没有任何参数。

我认为@Blender的答案是你最好的选择,试图在Python中模拟Clojure的线程函数。


1
2018-06-26 08:16





我想出了这个

def _composition(arg, *funcs_and_args):
    """
    _composition(
        [1,2,3], 
        (filter, lambda x: x % 2 == 1), 
        (map, lambda x: x+3)
    )
    #=> [4, 6]
    """
    for func_and_args in funcs_and_args:
        func, *b = func_and_args
        arg = func(*b, arg)
    return(arg)

0
2017-09-05 10:06





这似乎适用于简单的输入。不确定复杂输入的努力是否值得,例如, ((42, 'spam'), {'spam': 42})

def compose(function, *functions):
    return function if not functions else \
            lambda *args, **kwargs: function(compose(*functions)(*args, **kwargs))

def rcompose(*functions):
    return compose(*reversed(functions))

def postfix(arg, *functions):
    return rcompose(*functions)(arg)

例:

>>> postfix(1, str, len, hex)
'0x1'
>>> postfix(1, hex, len)
3

0
2018-01-13 05:51





我的 compose 返回函数的函数

def compose(*args):
    length = len(args)
    def _composeInner(lastResult, index):
        if ((length - 1) < index):
            return lastResult
        return _composeInner(args[index](lastResult), index + 1)

    return (lambda x: _composeInner(x, 0))

用法:

fn = compose(
        lambda x: x * 2,
        lambda x: x + 2,
        lambda x: x + 1,
        lambda x: x / 3
    )

result = fn(6) # -> 5

0
2018-06-20 12:18