这一直困扰着我一段时间。在学习Python之前我学习了Haskell,所以我一直喜欢将许多计算作为映射到列表中。这是由列表理解(我在这里给出pythonic版本)精美表达的:
result = [ f(x) for x in list ]
但在很多情况下,我们希望在x上执行多个语句,比如说:
result = [ f(g(h(x))) for x in list ]
这很快变得笨重,难以阅读。
我对此的正常解决方案是将其扩展回for循环:
result = []
for x in list:
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
result.append(x2)
关于这一点困扰我的一件事就是必须初始化空列表'结果'。这是一个微不足道的事情,但它让我感到不快。我想知道是否有任何替代等效形式。一种方法可能是使用本地函数(这是他们在Python中调用的吗?)
def operation(x):
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
return x2
result = [ operation(x) for x in list ]
上述两种形式中的任何一种都有什么特别的优点/缺点吗?或者是否有更优雅的方式?
答案 0 :(得分:5)
您可以轻松地在Python中执行函数组合。
这是一个创建新函数的方法的演示,该函数是现有函数的组合。
>>> def comp( a, b ):
def compose( args ):
return a( b( args ) )
return compose
>>> def times2(x): return x*2
>>> def plus1(x): return x+1
>>> comp( times2, plus1 )(32)
66
这是function composition更完整的食谱。这应该让它看起来不那么笨重。
答案 1 :(得分:3)
遵循最符合您口味的风格 我不担心表现;只有在你真正看到某些问题的情况下,你才能尝试转向不同的风格。
除了您的建议之外,还有其他一些可能的建议:
result = [f(
g(
h(x)
)
)
for x in list]
使用渐进式列表推导:
result = [h(x) for x in list]
result = [g(x) for x in result]
result = [f(x) for x in result]
同样,这只是风格和品味的问题。选择你最喜欢的那个,坚持下去: - )
答案 2 :(得分:2)
如果这是你经常做的事情,并且有几个不同的陈述,你可以写一些像
def seriesoffncs(fncs,x):
for f in fncs[::-1]:
x=f(x)
return x
其中fncs是一个函数列表。所以seriesoffncs((f,g,h),x)会返回 F(克(H(X)))。 这样,如果你以后在你的代码中需要锻炼h(q(g(f(x)))),你只需要执行seriesoffncs((h,q,g,f),x)而不是为一个新的操作函数每个功能组合。
答案 3 :(得分:1)
如果您只关注最后的结果,那么您的最后答案是最好的。对于任何看着它的人来说,这是很明显的。
我经常使用任何开始变得复杂的代码并将其移动到函数中。这基本上用作该代码块的注释。 (无论如何,任何复杂的代码都可能需要重写,并将它放在一个函数中,我可以返回并稍后处理它)
def operation(x):
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
return x2
result = [ operation(x) for x in list]
答案 4 :(得分:1)
dagw.myopenid.com函数的变体:
def chained_apply(*args):
val = args[-1]
for f in fncs[:-1:-1]:
val=f(val)
return val
现在你可以调用:
而不是seriesoffncs((h,q,g,f),x)result = chained_apply(foo, bar, baz, x)
答案 5 :(得分:1)
据我所知,Python中的组合没有内置/本机语法,但你可以编写自己的函数来编写东西而不会有太多麻烦。
def compose(*f):
return f[0] if len(f) == 1 else lambda *args: f[0](compose(*f[1:])(*args))
def f(x):
return 'o ' + str(x)
def g(x):
return 'hai ' + str(x)
def h(x, y):
return 'there ' + str(x) + str(y) + '\n'
action = compose(f, g, h)
print [action("Test ", item) for item in [1, 2, 3]]
当然,不需要在理解之外进行组合。
print [compose(f, g, h)("Test ", item) for item in [1, 2, 3]]
这种编写方式适用于任何数量的函数(以及递归限制),内部函数有任意数量的参数。
答案 6 :(得分:0)
有些情况下最好回到for-loop,是的,但更多时候我更喜欢这些方法之一:
使用适当的换行符和缩进来保持可读性:
result = [blah(blah(blah(x)))
for x in list]
或者提取(足够)逻辑到另一个函数中,正如您所提到的那样。但不一定是本地的;如果你能看到一种合理的方法来分解功能,那么Python程序员更喜欢从平面到嵌套结构。
我也从功能编程世界来到Python,并分享你的偏见。