10

我使用Python工作。最近,我發現了一個叫fn的精美小包。我一直在使用它來進行函數組合。Python中更好的函數組合

,而不是例如:

baz(bar(foo(x)))) 

與Fn鍵,你可以寫:

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

當我看到這個,我馬上想到的Clojure的:

(-> x foo bar baz) . 

但請注意,在Clojure中,輸入是在左邊。我想知道這是否可能在python/fn中。

+2

雖然操作符重載行爲是有趣的,對我來說這似乎只是一件壞事,在實際的代碼做。 –

+0

如果這就是你所要求的,沒有辦法在Python中使用精確的語法。您可以通過各種方式對其進行近似。什麼對你來說很重要? – BrenBarn

+0

保持流量從左到右。目前,對組合函數的爭論已經結束。如果我可以寫F()>> x >> foo >> bar >> baz或類似的話,它會更清晰。 –

回答

9

你不能複製確切的語法,但你可以做類似的東西:

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

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

    return result 

似乎工作:

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

你不能說確切的語法,雖然可以得到像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的回答有點不同,因爲它存儲的說法,以後可以具有不同功能的重新使用。

這有點像正常函數應用程序的反面:不是先指定函數,而是稍後指定一些參數,然後指定參數並稍後指定函數。這是一個有趣的玩具,但很難想象你爲什麼要這麼做。

1

如果你想使用fn,一個小黑客,你可以得到一個有點接近Clojure的語法:

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

看我怎麼在組合鏈的開始,將只返回x增加了一個功能當被調用時。這個問題是你仍然需要調用你的組合函數,只是沒有任何參數。

我認爲@ Blender的答案是您最好的選擇,試圖在Python中模擬Clojure的線程函數。

0

我想出了這個

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

這似乎爲簡單的輸入工作。不確定值得花費在複雜輸入上,例如((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