什么是函数式编程的“折叠”函数的“pythonic”?
在Haskell中实现类似以下内容的最习惯的方法是什么:
foldl (+) 0 [1,2,3,4,5] --> 15
或者在Ruby中相当于:
[1,2,3,4,5].inject(0) {|m,x| m + x} #> 15
很明显,Python提供了reduce
函数,这是fold的一个实现,正如上面那样,但是我被告知,pythonic的编程方式是避免lambda
项和高阶函数,在可能的情况下更喜欢list-comprehensions。 因此,是否有一种在Python中不是reduce
函数的列表或列表结构的优选方式,还是reduce
了实现这种方式的惯用方式?
总结一个数组的Pythonic方法是sum
。 为了其他目的,有时可以使用reduce
和operator
模块的一些组合,例如
def product(xs): return reduce(operator.mul, xs, 1)
请注意,在Haskell中, reduce
实际上是一个foldl
。 没有特别的语法来执行折叠,没有内置的折叠器,而实际上使用非关联运算符的foldr
被认为是不好的风格。
使用高阶函数是相当pythonic; 它充分利用了Python的原则,即一切都是一个对象,包括函数和类。 你是对的,lambda被一些Pythonistas皱起了眉头,但主要是因为它们在变得复杂的时候往往不易读。
哈斯克尔
foldl (+) 0 [1,2,3,4,5]
python
reduce(lambda a,b: a+b, [1,2,3,4,5], 0)
显然,这是一个微不足道的例子来说明一个观点。 在Python中,你只需要sum([1,2,3,4,5])
,甚至Haskell纯粹主义者通常更喜欢sum [1,2,3,4,5]
。
对于不存在明显的方便函数的非平凡场景,惯用的pythonic方法是明确地写出for循环,并使用可变variables赋值而不是使用reduce
或fold
。
这根本不是function性的风格,但那是“pythonic”方式。 Python不是为function纯粹主义者devise的。 了解Python如何利用stream控制的exception来了解非function性惯用python是如何实现的。
在Python 3中, reduce
已被删除: 发行说明 。 不过你可以使用functools模块
import operator, functools def product(xs): return functools.reduce(operator.mul, xs, 1)
另一方面,文件表示优先selectfor
-loop而不是reduce
,因此:
def product(xs): result = 1 for i in xs: result *= i return result
你也可以重新发明轮子:
def fold(f, l, a): """ f: the function to apply l: the list to fold a: the accumulator, who is also the 'zero' on the first call """ return a if(len(l) == 0) else fold(f, l[1:], f(a, l[0])) print "Sum:", fold(lambda x, y : x+y, [1,2,3,4,5], 0) print "Any:", fold(lambda x, y : x or y, [False, True, False], False) print "All:", fold(lambda x, y : x and y, [False, True, False], True) # Prove that result can be of a different type of the list's elements print "Count(x==True):", print fold(lambda x, y : x+1 if(y) else x, [False, True, True], 0)
这个(减less)问题的实际答案是:只要使用一个循环!
initial_value = 0 for x in the_list: initial_value += x #or any function.
这将比缩减更快,像PyPy这样的东西可以优化循环。
顺便说一下,和情况应该用sum
函数来解决
没有真正回答这个问题,但foldl和foldr的一行:
a = [8,3,4] ## Foldl reduce(lambda x,y: x**y, a) #68719476736 ## Foldr reduce(lambda x,y: y**x, a[::-1]) #14134776518227074636666380005943348126619871175004951664972849610340958208L