Ste*_*ken 84 python function python-3.x
在codewars.com上,我遇到了以下任务:
创建一个
add在连续调用时将数字相加的函数.所以add(1)应该回来1,add(1)(2)应该回来1+2,......
虽然我熟悉Python的基础知识,但我从来没有遇到过能够连续调用的函数f(x),即可以被称为的函数f(x)(y)(z)....到目前为止,我甚至不确定如何解释这种表示法.
作为一个数学家,我怀疑f(x)(y)是分配到每个功能x的函数g_{x},然后返回g_{x}(y),同样也f(x)(y)(z).
如果这种解释是正确的,Python将允许我动态创建对我来说非常有趣的函数.我在网上搜索过去一小时,但未能找到正确方向的领先优势.因为我不知道如何调用这个编程概念,所以这可能不会太令人惊讶.
你如何称呼这个概念,我在哪里可以阅读更多相关信息?
Jim*_*ard 94
我不知道这是否是函数链,就像它的可调用链一样,但是,因为函数是可调用的,我想这没有什么坏处.无论哪种方式,有两种方法我可以想到这样做:
int和定义__call__:第一种方法是使用自定义int子类定义__call__哪个子类返回具有更新值的新实例:
class CustomInt(int):
def __call__(self, v):
return CustomInt(self + v)
Run Code Online (Sandbox Code Playgroud)
add现在可以定义函数以返回一个CustomInt实例,该实例可以连续调用,作为返回其自身更新值的可调用对象:
>>> def add(v):
... return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44) # and so on..
50
Run Code Online (Sandbox Code Playgroud)
另外,作为一个int子类中,返回的值保留__repr__和__str__行为int秒.但是,对于更复杂的操作,您应该适当地定义其他dunders.
正如@Caridorc在评论中指出的那样,add也可以简单地写成:
add = CustomInt
Run Code Online (Sandbox Code Playgroud)
重命名类add而不是CustomInt也类似.
我能想到的另一种方法涉及一个嵌套函数,它需要一个额外的空参数调用才能返回结果.我没有使用nonlocal并选择将属性附加到函数对象以使其在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
Run Code Online (Sandbox Code Playgroud)
这会连续返回self(_inner_adder),如果val提供了a ,则递增it(_inner_adder += val),如果不是,则返回值.就像我提到的,它需要额外的()调用才能返回递增的值:
>>> add(1)(2)()
3
>>> add(1)(2)(3)() # and so on..
6
Run Code Online (Sandbox Code Playgroud)
Jor*_*zov 23
你可以恨我,但这是一个单行:)
add = lambda v: type("", (int,), {"__call__": lambda self, v: self.__class__(self + v)})(v)
Run Code Online (Sandbox Code Playgroud)
编辑:好的,这是如何工作的?代码与@Jim的答案相同,但一切都在一行上发生.
type可用于构造新类型:type(name, bases, dict) -> a new type.因为name我们提供空字符串,因为在这种情况下不需要名称.对于bases(元组)我们提供一个(int,),与继承相同int.dict是类属性,我们附加__call__lambda.self.__class__(self + v) 是完全相同的 return CustomInt(self + v)Kas*_*mvd 16
如果要定义要多次调用的函数,首先需要每次返回一个可调用对象(例如函数),否则必须通过定义__call__属性来创建自己的对象,以使其可调用.
下一点是您需要保留所有参数,在这种情况下,您可能希望使用Coroutines或递归函数.但请注意,Coroutines比递归函数更加优化/灵活,特别是对于此类任务.
这是一个使用Coroutines的示例函数,它保留了自身的最新状态.请注意,它不能被多次integer调用,因为返回值是不可调用的,但您可能会考虑将其转换为您期望的对象;-).
def add():
current = yield
while True:
value = yield current
current = value + current
it = add()
next(it)
print(it.send(10))
print(it.send(2))
print(it.send(4))
10
12
16
Run Code Online (Sandbox Code Playgroud)
小智 8
简单地:
class add(int):
def __call__(self, n):
return add(self + n)
Run Code Online (Sandbox Code Playgroud)
如果您愿意接受额外()的费用以检索结果,您可以使用functools.partial:
from functools import partial
def add(*args, result=0):
return partial(add, result=sum(args)+result) if args else result
Run Code Online (Sandbox Code Playgroud)
例如:
>>> 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
Run Code Online (Sandbox Code Playgroud)
这也允许一次指定多个数字:
>>> add(1, 2, 3)(4, 5)(6)()
21
Run Code Online (Sandbox Code Playgroud)
如果要将其限制为单个数字,可以执行以下操作:
def add(x=None, *, result=0):
return partial(add, result=x+result) if x is not None else result
Run Code Online (Sandbox Code Playgroud)
如果您想add(x)(y)(z)轻松地返回结果并进一步调用,那么子类化int是一种可行的方法。
这样做的pythonic方法是使用动态参数:
def add(*args):
return sum(args)
Run Code Online (Sandbox Code Playgroud)
这不是你正在寻找的答案,而且你可能知道这一点,但我认为无论如何我会放弃它,因为如果有人想知道这样做不是出于好奇而是出于工作.他们应该有"正确的事情"回答.
| 归档时间: |
|
| 查看次数: |
24461 次 |
| 最近记录: |