English 中文(简体)
映射一系列语句的最Pythonic形式是什么?
原标题:
  • 时间:2008-12-09 08:06:41
  •  标签:

这是让我困扰了一段时间的事情。在学习Python之前,我学习了Haskell,所以我一直喜欢将许多计算视为映射到列表的方式。这可以通过列表推导式来精美地表达(这里是Python风格的版本):

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)

关于这个事情,让我非常困扰的是必须初始化空列表 result。这是一个琐事,但却让我不开心。我在想是否有任何其他等价的形式。一种方法可能是使用本地函数(Python 中是否称为这个?)

def operation(x):
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  return x2
result = [ operation(x) for x in list ]

这两种形式有特别的优缺点吗?或者也许有更加优美的方式?

问题回答

你可以在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

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

Follow the style that most matches your tastes.
I would not worry about performance; only in case you really see some issue you can try to move to a different style.

这里有一些其他可能的建议,除了你的提议之外:

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]

再说,那只是一种风格和口味的问题。选择你最喜欢的那个,并坚持它 :-)

如果这是你经常做并且有几个不同的声明,你可以写些类似的东西。

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

where fncs is a list of functions. so seriesoffncs((f,g,h),x) would return f(g(h(x))). This way if you later in your code need to workout h(q(g(f(x)))) you would simply do seriesoffncs((h,q,g,f),x) rather than make a new operations function for each combination of functions.

如果你只关心最后的结果,那么你的最后一个答案是最好的。对于任何人来说,这都是清晰明了的。

我经常将任何开始变得复杂的代码移动到函数中。这基本上就像是对那一段代码的注释。 (任何复杂的代码可能需要重新编写,并将其放在一个函数中,我可以随后回来处理它)

def operation(x):
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  return x2
result = [ operation(x) for x in list]

一个变体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)

据我所知,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) +  
 

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]]

这种编写方式适用于任何数量的函数(好的,最多到递归限制),并且适用于内部函数的任何数量参数。

有些情况下最好回到for循环,但更常见的是我更喜欢以下方法之一:

使用适当的换行和缩进使其易于阅读。

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

或者提取(足够的)逻辑到另一个函数中,就像你所提到的一样。但不一定是本地的;如果你能够发现一个合理的方法来因素化功能,Python程序员更喜欢扁平而不是嵌套的结构。

我也是从函数式编程世界转向 Python 的,并分享你的偏见。





相关问题
热门标签