在 Haskell 中实现以下目标的最惯用方法是什么:
foldl (+) 0 [1,2,3,4,5]
--> 15
或者在 Ruby 中等效:
[1,2,3,4,5].inject(0) {|m,x| m + x}
#> 15
显然,Python提供了reduce
函数,它是折叠的实现,与上面完全一样,但是,我被告知“pythonic”编程方式是避免lambda
术语和高阶函数,在可能的情况下更喜欢列表推导。因此,是否有一种折叠列表的首选方法,或者 Python 中类似列表的结构不是 reduce 函数,或者 reduce
是实现此目的的惯用方式?
对数组求和的 Pythonic 方法是使用 sum
。对于其他目的,您有时可以使用reduce
(来自functools
模块)和运算符
模块的某种组合,例如:
def product(xs):
return reduce(operator.mul, xs, 1)
请注意,用Haskell的术语来说,< code>reduce实际上是一个< code>foldl。没有特殊的语法来执行折叠,没有内置的< code>foldr,实际上使用< code>reduce和非关联操作符被认为是不好的风格。
使用高阶函数是一种非常单调的行为;它很好地利用了Python的原理,即一切都是一个对象,包括函数和类。你说的没错,一些Pythonista不喜欢lambdas,但主要是因为当它们变得复杂时,它们往往不太可读。
从 Python 3.8
开始,引入赋值表达式 (PEP 572) (:=
运算符),它提供了命名表达式结果的可能性,我们可以使用列表推导来复制其他语言称为折叠/折叠左/减少操作:
给定一个列表、一个归约函数和一个累加器:
items = [1, 2, 3, 4, 5]
f = lambda acc, x: acc * x
accumulator = 1
我们可以用 f
折叠项目
以获得结果累积
:
[accumulator := f(accumulator, x) for x in items]
# accumulator = 120
或以浓缩的形式:
acc = 1; [acc := acc * x for x in [1, 2, 3, 4, 5]]
# acc = 120
注意,这实际上也是一个“scanleft”操作,因为列表理解的结果代表了每一步的累积状态:
acc = 1
scanned = [acc := acc * x for x in [1, 2, 3, 4, 5]]
# scanned = [1, 2, 6, 24, 120]
# acc = 120
哈斯克尔
< code>foldl ( ) 0 [1,2,3,4,5]
蟒蛇
< code>reduce(lambda a,b: a b,[1,2,3,4,5],0)
显然,这是说明一个观点的一个微不足道的例子。在Python中,你只需要做< code>sum([1,2,3,4,5]),甚至Haskell纯粹主义者通常更喜欢< code>sum [1,2,3,4,5]。
对于没有明显便利函数的重要场景,惯用的pythonic方法是显式写出For循环,并使用可变变量赋值,而不是使用< code>reduce或< code>fold。
这根本不是功能性的风格,而是“蟒蛇式”的风格。Python不是为功能纯粹主义者设计的。了解Python如何支持流控制的异常,以了解Python的非功能惯用用法。