【问题标题】:Better Function Composition in PythonPython 中更好的函数组合
【发布时间】:2013-06-23 19:22:36
【问题描述】:

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

例如,而不是:

baz(bar(foo(x))))

用fn,你可以写:

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

看到这里,我立刻想到了 Clojure:

(-> x foo bar baz) .

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

【问题讨论】:

  • 虽然运算符重载行为很有趣,但对我来说,这在实际代码中似乎是一件坏事。
  • 如果这就是您所要求的,则无法在 Python 中使该精确语法工作。您可以通过各种方式对其进行近似。语法方面对你来说究竟什么是重要的?
  • 保持从左到右的流动。目前,组合函数的参数位于末尾。如果我可以写 F() >> x >> foo >> bar >> baz 或类似的东西会更清楚。

标签: python clojure functional-programming function-composition


【解决方案1】:

你无法复制确切的语法,但你可以做出类似的东西:

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 的答案有点不同,因为它存储了参数,以后可以在不同的函数中重复使用。

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        【解决方案4】:

        我想出了这个

        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)
        

        【讨论】:

          【解决方案5】:

          这似乎适用于简单的输入。不确定是否值得为复杂的输入付出努力,例如,((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
          

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              【解决方案7】:

              我明白你的意思。这没有意义。在我看来这个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)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-05-20
                • 2019-08-17
                • 1970-01-01
                • 2021-01-17
                相关资源
                最近更新 更多