簡體   English   中英

Python 中更好的函數組合

[英]Better Function Composition in Python

我在 Python 中工作。 最近,我發現了一個很棒的小包,叫做fn 我一直將它用於函數組合。

例如,而不是:

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})

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

我的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

我明白你的意思。 這沒有意義。 在我看來,這個 python 庫做得更好。

>>> from compositions.compositions import Compose
>>> foo = Compose(lambda x:x)
>>> foo = Compose(lambda x:x**2)
>>> foo = Compose(lambda x:sin(x))
>>> (baz*bar*foo)(x)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM