我有一些代码,其中我最终得到了二进制函数列表和值列表,我需要像这样链接调用:
funs = [..]
vals = [..]
result = funs[0](vals[0],
funs[1](vals[1],
..
funs[-1](vals[-2], vals[-1])))))..)
举一个简单的例子,如果:
funs = [operator.add, operator.mul]
vals = [1, 2, 3]
然后result
应该最终评估add(1, mul(2, 3))
,结果为7.我可以编写一个for
循环来评估每个中间结果,这同时也很容易且令人难以置信地不满意:
result = vals[-1]
for val, fun in reversed(zip(vals[:-1], funs)):
result = fun(val, result)
Pythonic的方式是什么?或者这样就好了吗?
答案 0 :(得分:2)
这似乎与reduce
非常相似,但每次使用的函数都不同,因此一种解决方案是创建一个每次调用时都使用不同函数的对象:
class Cycled_Functions:
def __init__(self,functions):
self.functions = iter(functions)
def __call__(self,*args,**kw):
f = next(self.functions) #will raise StopIteration at some point
return f(*args,**kw)
然后Cycled_Functions(reversed(FUNCTIONS))
适合与reduce
一起使用来完成您的任务:
import operator
from functools import reduce
funs = [operator.add, operator.mul]
vals = [1, 2, 3]
f = Cycled_Functions(reversed(funs))
print(reduce(f, reversed(vals)))
我仍然更喜欢你拥有的基本循环,但这是另一种选择,我觉得它值得提供。
答案 1 :(得分:1)
您提供的解决方案对我来说似乎是Pythonic。我不确定你为什么认为不是。人们在评论中提到了reduce(),但reduce() is considered non-Pythonic by Guido van Rossum并且我认为当迭代解决方案成为可能时,它的变化也是如此。对于它的价值,您可以使用reduce()来编写它,但是:
def foo(funs, vals):
"""
>>> import operator
>>> funs = [operator.add, operator.mul]
>>> vals = [1, 2, 3]
>>> foo(funs, vals)
7
"""
return reduce(lambda z, (fun, val): fun(val, z), reversed(zip(funs, vals[:-1])), vals[-1])
为了说明,您可以将其写为递归函数,但递归比迭代慢,并且受到调用堆栈大小限制的限制。
def foo(funs, vals):
"""
>>> import operator
>>> funs = [operator.add, operator.mul]
>>> vals = [1, 2, 3]
>>> foo(funs, vals)
7
"""
if len(funs) > 1:
fun, val = funs[0], vals[0]
return fun(val, foo(funs[1:], vals[1:]))
else:
[fun] = funs
return fun(*vals)