Python中更好的函数组合

Python中更好的函数组合,python,clojure,functional-programming,function-composition,Python,Clojure,Functional Programming,Function Composition,我在Python中工作。最近,我发现了一个很棒的小包装,叫做。我一直在用它来合成函数 例如,而不是: baz(bar(foo(x)))) 使用fn,您可以编写: (F() >> foo >> bar >> baz)(x) . 当我看到这一幕时,我立刻想到了Clojure: (-> x foo bar baz) . 但请注意,在Clojure中,输入是如何位于左侧的。我想知道这在python/fn中是否可行。您不能复制确切的语法,但可以制作类似的东西

我在Python中工作。最近,我发现了一个很棒的小包装,叫做。我一直在用它来合成函数

例如,而不是:

baz(bar(foo(x))))
使用fn,您可以编写:

(F() >> foo >> bar >> baz)(x) .
当我看到这一幕时,我立刻想到了Clojure:

(-> x foo bar baz) .

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

您不能复制确切的语法,但可以制作类似的东西:

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

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

    return result
似乎有效:

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

虽然可以得到类似于
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的答案有点不同,因为它存储参数,以后可以与不同的函数一起重复使用


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

如果你想使用
fn
,稍加修改,你可以更接近Clojure语法:

>>> def r(x): return lambda: x
>>> (F() >> r(x) >> foo >> bar >> baz)()
查看我如何在合成链的开头添加了另一个函数,调用该函数时只返回
x
。这样做的问题是,您仍然需要调用组合函数,而不需要任何参数

我认为@Blender的答案是您尝试在Python中模仿Clojure的线程函数的最佳选择。

我想到了这个

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)

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

例如:

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

返回函数的My
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))

我明白你的意思。这没有道理。在我看来,这个python库 做得更好

>>来自compositions.compositions导入Compose
>>>foo=Compose(λx:x)
>>>foo=Compose(λx:x**2)
>>>foo=Compose(λx:sin(x))
>>>(baz*bar*foo)(x)

虽然运算符重载行为很有趣,但对我来说,在实际代码中这样做似乎是一件坏事。如果你问的是这个问题的话,在Python中没有办法实现精确的语法。你可以用各种方法来近似它。在语法方面,什么对您来说非常重要?保持从左到右的流。目前,组合函数的参数已结束。如果我能写F()>>x>>foo>>bar>>baz或类似的东西,就会更清楚。
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