Accumulate 不适用于求和,但适用于等效的 lambda 函数。为什么?

Accumulate does not work with sum, but does work with equivalent lambda function. Why?

我在玩累加函数,我认为 accumulate(<int[]>,sum) 会产生一个累加和。但是,运行使用以下代码会导致错误。

from itertools import accumulate
print([*accumulate([1,2,3],sum)])

具体来说,我得到 TypeError: 'int' object is not iterable。另一方面,运行使用 lambda 函数执行完全相同的操作会产生预期的结果。

from itertools import accumulate
print([*accumulate([1,2,3],lambda *args:sum(args))])
# [1, 3, 6]

当我运行这段代码使用一个命名的自定义函数做同样的事情时,我得到了另一个奇怪的结果。

from itertools import accumulate    
def my_sum(*args): return sum(args)
print([*accumulate([1,2,3]),my_sum])
#[1, 3, 6, <function my_sum at 0x7fd57139caf0>]

尚不清楚是什么导致了行为上的差异。 sum,my_sum, 和匿名函数属于“函数”类型,因此类型本身并不能决定事情。我还做了以下事情,看看我是否能得到其他线索;我注意到的唯一区别是 sum 是内置函数。

print(lambda *args:sum(args),my_sum,sum,sep='\n')
# <function <lambda> at 0x7fd57139cb80>
# <function my_sum at 0x7fd57139cc10>
# <built-in function sum>

这是怎么回事?

来自docs:对于itertools.accumulate(iterable[, func, *, initial=None])

If func is supplied, it should be a function of two arguments. Elements of the input iterable may be any type that can be accepted as arguments to func. (For example, with the default operation of addition, elements may be any addable type including Decimal or Fraction.)

sum() 确实接受两个参数,但第一个参数 必须 是一个可迭代的,第二个是起始值。 Docs

让我们通过打印 my_sum()

中的参数,看看 accumulate() 传递给它的 func 参数的内容
def my_sum(*args):
    print(args)
    return sum(args)

accumulate([1, 2, 3], my_sum)
# (1, 2)
# (3, 3)

因此accumulate()将最后一个累加值和下一个数字传递给func。由于 sum() 的第一个参数必须是可迭代的(int 不是),你会得到那个错误。

你的 lambda 等同于 sum()sum() 需要 一个可迭代的 和 returns 其元素的总和。您的 lambda 接受 任意数量的参数 和 returns 这些参数的总和。要对此进行测试,请查看执行 sum([1, 2, 3])my_sum([1, 2, 3]).

时得到的结果

在你的最后一个例子中你有一个错字。您没有将 my_sum 传递给 accumulate()。您创建了一个列表,其中包含 accumulate([1, 2, 3]) 的结果,然后是函数 my_sum。将其修复为 print([*accumulate([1,2,3], my_sum)]),您将获得与 lambda 情况相同的输出。

请注意,不提供 func 的行为就好像 func=operator.add 一样,并且会给您一个累计金额。

>>> accumulate([1, 2, 3])
[1, 3, 6]