Python中的函数链接

Python中的函数链接,python,function,python-3.x,Python,Function,Python 3.x,在上,我遇到了以下任务: 创建一个函数add,在连续调用时将数字相加。所以add(1)应该返回1,add(1)(2)应该返回1+2 虽然我熟悉Python的基础知识,但我从未遇到过能够连续调用的函数,即可以称为f(x)(y)(z)的函数f(x)。到目前为止,我甚至不知道如何解释这个符号 作为一名数学家,我怀疑f(x)(y)是一个函数,它为每个x分配一个函数g{x},然后返回g{x}(y),对于f(x)(y)(z) 如果这种解释是正确的,Python将允许我动态创建对我来说非常有趣的函数。我在网上

在上,我遇到了以下任务:

创建一个函数
add
,在连续调用时将数字相加。所以
add(1)
应该返回
1
add(1)(2)
应该返回
1+2

虽然我熟悉Python的基础知识,但我从未遇到过能够连续调用的函数,即可以称为
f(x)(y)(z)
的函数
f(x)
。到目前为止,我甚至不知道如何解释这个符号

作为一名数学家,我怀疑
f(x)(y)
是一个函数,它为每个
x
分配一个函数
g{x}
,然后返回
g{x}(y)
,对于
f(x)(y)(z)

如果这种解释是正确的,Python将允许我动态创建对我来说非常有趣的函数。我在网上搜索了一个小时,但是没有找到正确方向的线索。然而,由于我不知道这个编程概念是如何被称为的,这可能并不太令人惊讶


你如何称呼这个概念?我在哪里可以读到更多关于它的内容?

我不知道这是否是函数链接,也不知道它是可调用链接,但是,既然函数是可调用的,我想这不会造成什么伤害。无论哪种方式,我都可以想到两种方法:

子分类
int
和定义
调用
第一种方法是使用自定义的
int
子类,该子类定义使用更新的值返回自身的新实例:

class CustomInt(int):
    def __call__(self, v):
        return CustomInt(self + v)
>>> add(1)(2)()
3
>>> add(1)(2)(3)()  # and so on..
6
现在可以定义函数
add
来返回
CustomInt
实例,该实例作为返回自身更新值的可调用实例,可以连续调用:

>>> def add(v):
...    return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44)  # and so on..
50
此外,作为
int
子类,返回值保留
int
repr\uuu
\uu str\uu
行为。但是,对于更复杂的操作,您应该适当地定义其他Dunder

正如@Caridorc在评论中指出的,
add
也可以简单地写成:

add = CustomInt 
将类重命名为
add
,而不是
CustomInt
,也同样有效


定义一个闭包,需要额外调用以产生值: 我能想到的另一种方法是使用嵌套函数,它需要额外的空参数调用才能返回结果。我正在使用
非本地
并选择将属性附加到函数对象,以使其在python之间可移植:

def add(v):
    def _inner_adder(val=None):  
        """ 
        if val is None we return _inner_adder.v 
        else we increment and return ourselves
        """
        if val is None:    
            return _inner_adder.v
        _inner_adder.v += val
        return _inner_adder
    _inner_adder.v = v  # save value
    return _inner_adder 
这会连续返回自身(
\u inner\u adder
),如果提供了
val
,则将其递增(
\u inner\u adder+=val
),如果没有,则按原样返回值。正如我提到的,它需要额外的
()
调用才能返回递增的值:

class CustomInt(int):
    def __call__(self, v):
        return CustomInt(self + v)
>>> add(1)(2)()
3
>>> add(1)(2)(3)()  # and so on..
6

如果要定义要多次调用的函数,首先需要每次返回一个可调用对象(例如函数),否则必须通过定义
\uuuu call\uuu
属性来创建自己的对象,才能调用它

下一点是您需要保留所有参数,在本例中,这意味着您可能需要使用或递归函数。但请注意,协程比递归函数优化/灵活得多,特别是对于此类任务

下面是一个使用协程的示例函数,它保留了自身的最新状态。请注意,它不能被多次调用,因为返回值是一个不可调用的
整数
,但您可能会考虑将其转换为预期对象;-)


你可以恨我,但这里有一句话:)

编辑:好的,这是怎么回事?代码与@Jim的答案相同,但所有事情都发生在一行上

  • type
    可用于构造新类型:
    type(name、base、dict)->新类型
    。对于
    name
    我们提供了空字符串,因为在这种情况下并不真正需要name。对于
    base
    (tuple),我们提供了一个
    (int,)
    ,它与继承
    int
    相同
    dict
    是类属性,我们在其中附加
    \uuuu调用\uuuu
    lambda
  • self.\uuuu类(self+v)
    return CustomInt(self+v)
  • 新类型在外部lambda中构造并返回

  • python的方法是使用动态参数:

    def add(*args):
        return sum(args)
    
    这不是你想要的答案,你可能知道这一点,但我想我还是会给出它,因为如果有人想这样做不是出于好奇,而是为了工作。他们可能应该有“正确的事情做”的答案。

    简单地说:

    class add(int):
       def __call__(self, n):
          return add(self + n)
    

    如果您愿意接受额外的
    ()
    以检索结果,您可以使用:

    例如:

    >>> add(1)
    functools.partial(<function add at 0x7ffbcf3ff430>, result=1)
    >>> add(1)(2)
    functools.partial(<function add at 0x7ffbcf3ff430>, result=3)
    >>> add(1)(2)()
    3
    
    如果要将其限制为单个数字,可以执行以下操作:

    def add(x=None, *, result=0):
        return partial(add, result=x+result) if x is not None else result
    

    如果您希望
    add(x)(y)(z)
    随时返回结果并可进一步调用,那么子分类
    int
    就是一种方法。

    看起来您正在寻找currying函数。t:嵌套函数是动态创建的,可以访问其父函数的局部变量,并且可以作为(可调用)函数返回对象。@JonathonReinhart这就是我思考问题的方式。但我并没有真正了解如何实现它。顺便说一句:Python肯定会允许您动态创建函数。如果你感兴趣,这里有几个相关的概念可以阅读:| | |@LukasGraf我来看看。非常感谢。在交互式代码中,
    add=CostumInt
    应该也能工作并且更简单。子类化内置代码的问题是,
    (2*add(1)(2))(3)
    失败并出现
    TypeError
    ,因为
    int
    不可调用。基本上,
    CustomInt
    在我使用时被转换成普通的
    int
    >>> add(1, 2, 3)(4, 5)(6)()
    21
    
    def add(x=None, *, result=0):
        return partial(add, result=x+result) if x is not None else result