【问题标题】:How to create a function that applies a function to the inputs of another function in Python?如何创建一个函数,将一个函数应用于 Python 中另一个函数的输入?
【发布时间】:2021-03-22 09:52:02
【问题描述】:

我正在寻找一种很好的实用方法来执行以下操作:

def add(x, y):
    return x + y

def neg(x):
    return -x

def c(x, y):
    # Apply neg to inputs for add
    _x = neg(x)
    _y = neg(y)

    return add(_x, _y)

neg_sum = c(2, 2)   # -4

这似乎与柯里化有关,但我能找到的所有示例都使用只有一个输入变量的函数。我想要看起来像这样的东西:

def add(x, y):
    return x + y

def neg(x):
    return -x

c = apply(neg, add)
neg_sum = c(2, 2)   # -4

【问题讨论】:

  • 您希望apply(g, f) 创建一个新函数c,将函数g 应用于其所有参数,然后将结果传递给函数f。这假设函数 cf 接受相同数量的参数(可能是多个),并且 cf 都返回一个值。那正确吗?我觉得可能还有其他一些情况,你想构造f(g(h(x)), g(h(y)))h(f(g(x), g(y))),这可能没有足够的对称性。或者,如果您只是多次调用apply,有时使用单参数函数,也许它确实如此。

标签: python functional-programming currying


【解决方案1】:

根据 Matthias Fripp 的回答,我问自己:我想同时编写 addnegadd_neg(*args)neg_add(*args)。这需要稍微修改一下 Matthias 的建议。这个想法是为了获得一些关于要组合的函数的数量(args 数量)的提示。由于inspect 模块,这些信息是通过一些内省获得的。考虑到这一点,我们调整了 args 通过函数链的方式。这里的主要假设是,我们处理的是数学意义上的实函数,即返回 ONE 浮点数并至少接受一个参数的函数。

from functools import reduce
from inspect import getfullargspec


def arity_one(func):
    spec = getfullargspec(func)
    return len(spec[0])==1 and spec[1] is None

def add(*args):
    return reduce(lambda x,y:x+y, args, 0)

def neg(x):
    return -x

def compose(fun1,fun2):
    def comp(*args):
        if arity_one(fun2): return fun1(*(map( fun2, args)))
        else: return fun1(fun2(*args))
    return comp


neg_add = compose(neg, add)
add_neg = compose(add, neg)

print(f"-2+(-3) = {add_neg(2, 3)}")
print(f"-(2+3) = {neg_add(2, 3)}")

解决方案还是很临时的……

【讨论】:

    【解决方案2】:

    这是一种相当直接的方法:

    def add(x, y):
        return x + y
    
    def neg(x):
        return -x
    
    def apply(g, f):
        # h is a function that returns
        # f(g(arg1), g(arg2), ...)
        def h(*args):
            return f(*map(g, args))
        return h
    
    # or this:
    # def apply(g, f):
    #    return lambda *args: f(*map(g, args))
    
    c = apply(neg, add)
    neg_sum = c(2, 2)   # -4
    

    请注意,当您在函数定义中使用*myvar 作为参数时,myvar 将成为接收到的所有非关键字参数的列表。如果您以*expression 作为参数调用函数,则expression 中的所有项目都将被解包并作为单独的参数发送给函数。我使用这两种行为使h 接受未知的参数列表,然后将函数g 应用于每个(使用map),然后将它们作为参数传递给f

    【讨论】:

    • 详细说明您的答案:您将如何编写适用于 add_neg = compose(add, neg)neg_add = compose(neg,add) 的 compose 函数?
    【解决方案3】:

    根据您需要的可扩展性,另一种方法是创建一个对象,该对象实现您的运算符方法,每个方法返回相同的对象,允许您以任意顺序将运算符链接在一起。

    如果你能应付它总是返回一个列表,你也许可以让它工作。

    class mathifier:
    
        def __init__(self,values):
            self.values = values
    
        def neg(self):
            self.values = [-value for value in self.values]
            return self
    
        def add(self):
            self.values = [sum(self.values)]
            return self
             
    print (mathifier([2,3]).neg().add().values)
    

    您仍然可以为任何一组链式函数获取命名函数:

    neg_add = lambda x : mathifier(x).neg().add()
    
    print(neg_add([2,3]).values)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      • 2020-11-22
      • 1970-01-01
      • 2022-11-04
      • 1970-01-01
      相关资源
      最近更新 更多