0

这是困扰我一段时间的事情。我在学习 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 ]

上述两种形式中的任何一种都有什么特别的优点/缺点吗?还是有更优雅的方式?

4

7 回答 7

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

这是一个更完整的函数组合配方。这应该使它看起来不那么笨重。

于 2008-12-09T15:11:15.917 回答
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]

同样,这只是风格和品味的问题。选择你最喜欢的那个,然后坚持下去:-)

于 2008-12-09T09:25:04.947 回答
2

如果这是你经常做的事情,并且有几个不同的陈述,你可以写类似的东西

def seriesoffncs(fncs,x):
    for f in fncs[::-1]:
        x=f(x)
    return x

其中 fncs 是函数列表。所以 seriesoffncs((f,g,h),x) 将返回 f(g(h(x)))。这样,如果您稍后在代码中需要锻炼 h(q(g(f(x)))) 您只需执行 seriesoffncs((h,q,g,f),x) 而不是为每个功能组合。

于 2008-12-09T15:35:13.887 回答
1

如果您只关心最后的结果,那么您的最后一个答案是最好的。任何看到它的人都清楚你在做什么。

我经常将任何开始变得复杂的代码移到一个函数中。这基本上用作该代码块的注释。(无论如何,任何复杂的代码都可能需要重新编写,并将其放入一个函数中,我可以稍后再回去处理)

def operation(x):
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  return x2
result = [ operation(x) for x in list]
于 2008-12-09T08:34:29.090 回答
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)
于 2008-12-09T18:20:06.177 回答
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]]

这种组合方式适用于任何数量的函数(嗯,直到递归限制),内部函数具有任意数量的参数。

于 2009-01-02T14:41:29.913 回答
0

在某些情况下,最好回到 for 循环,是的,但更多时候我更喜欢以下方法之一:

使用适当的换行符和缩进来保持可读性:

result = [blah(blah(blah(x)))
          for x in list]

正如您所提到的,或者将(足够的)逻辑提取到另一个函数中。但不一定是本地的;如果你能找到一种合理的方式来分解功能,Python 程序员更喜欢平面结构而不是嵌套结构。

我也是从函数式编程世界来到 Python 的,并且和你一样有偏见。

于 2008-12-09T08:26:04.160 回答