Python中的函数链
问题描述
在 Codewars.com 我遇到了以下任务:
On Codewars.com I encountered the following task:
创建一个函数add
,在连续调用时将数字相加.所以 add(1)
应该返回 1
,add(1)(2)
应该返回 1+2
,...
Create a function
add
that adds numbers together when called in succession. Soadd(1)
should return1
,add(1)(2)
should return1+2
, ...
虽然我熟悉 Python 的基础知识,但我从未遇到过能够连续调用的函数,即可以调用的函数 f(x)
f(x)(y)(z)...
.到目前为止,我什至不确定如何解释这个符号.
While I'm familiar with the basics of Python, I've never encountered a function that is able to be called in such succession, i.e. a function f(x)
that can be called as f(x)(y)(z)...
. Thus far, I'm not even sure how to interpret this notation.
作为一名数学家,我怀疑 f(x)(y)
是一个函数,它为每个 x
分配一个函数 g_{x}
然后返回 g_{x}(y)
和 f(x)(y)(z)
.
As a mathematician, I'd suspect that f(x)(y)
is a function that assigns to every x
a function g_{x}
and then returns g_{x}(y)
and likewise for f(x)(y)(z)
.
如果这种解释是正确的,Python 将允许我动态创建对我来说非常有趣的函数.在过去的一个小时里,我在网上搜索了一个小时,但无法找到正确方向的线索.不过,由于我不知道这个编程概念是如何被调用的,所以这可能不会太令人惊讶.
Should this interpretation be correct, Python would allow me to dynamically create functions which seems very interesting to me. I've searched the web for the past hour, but wasn't able to find a lead in the right direction. Since I don't know how this programming concept is called, however, this may not be too surprising.
你如何称呼这个概念,我在哪里可以阅读更多关于它的信息?
How do you call this concept and where can I read more about it?
解决方案
我不知道这是 function 链接和 callable 链接一样多,但是,因为函数 是 可调用的,我想这并没有什么坏处.无论哪种方式,我都可以想到两种方法:
I don't know whether this is function chaining as much as it's callable chaining, but, since functions are callables I guess there's no harm done. Either way, there's two ways I can think of doing this:
第一种方法是使用定义 int 子类="noreferrer">__call__
返回一个新的自身实例,并带有更新后的值:
The first way would be with a custom int
subclass that defines __call__
which returns a new instance of itself with the updated value:
class CustomInt(int):
def __call__(self, v):
return CustomInt(self + v)
add
函数现在可以定义为返回一个 CustomInt
实例,该实例作为返回自身更新值的可调用对象,可以连续调用:
Function add
can now be defined to return a CustomInt
instance, which, as a callable that returns an updated value of itself, can be called in succession:
>>> 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__
和__str__
行为s.但对于更复杂的操作,您应该适当地定义其他 dunders.
In addition, as an int
subclass, the returned value retains the __repr__
and __str__
behavior of int
s. For more complex operations though, you should define other dunders appropriately.
正如@Caridorc 在评论中指出的那样,add
也可以简单地写成:
As @Caridorc noted in a comment, add
could also be simply written as:
add = CustomInt
将类重命名为 add
而不是 CustomInt
也可以类似地工作.
Renaming the class to add
instead of CustomInt
also works similarly.
我能想到的唯一其他方法涉及一个嵌套函数,该函数需要一个额外的空参数调用才能返回结果.我不使用 nonlocal
并选择将属性附加到函数对象以使其在 Python 之间可移植:
The only other way I can think of involves a nested function that requires an extra empty argument call in order to return the result. I'm not using nonlocal
and opt for attaching attributes to the function objects to make it portable between Pythons:
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
这会不断返回自身 (_inner_adder
),如果提供了 val
,则将其递增 (_inner_adder += val
),否则, 按原样返回值.就像我提到的,它需要一个额外的 ()
调用才能返回递增的值:
This continuously returns itself (_inner_adder
) which, if a val
is supplied, increments it (_inner_adder += val
) and if not, returns the value as it is. Like I mentioned, it requires an extra ()
call in order to return the incremented value:
>>> add(1)(2)()
3
>>> add(1)(2)(3)() # and so on..
6
相关文章