从函数自身的输出中累加函数



我有以下生成器,它有点像itertools.accumulate,只是它从函数自己的输出中获取下一个输入,而不是可迭代的:

def turboaccumulate(f, *, initial):
x = initial
while True:
x = f(x)
yield x

标准库中是否包含类似的内容,或者Python文档中是否包含推荐的配方?我在大约20分钟的搜索中找不到一个。

或者,至少:这个操作叫什么(我高度怀疑"涡轮累积"是公认的名称。(


这篇文章的背景是努力将这里难以理解的lisp庞然大物解析为凡人可以理解的东西,我归结为:

def blum_blum_shub(p, q, s):
#assert gcd(p*q, s) == 1
#assert p % 4 == 3 and q % 4 == 3
#assert s not in {0, 1}
M = p * q
yield from turboaccumulate(lambda x: pow(x, 2, M), initial=s)

然而,最后一个函数调用看起来非常愚蠢,所以我想知道它是否存在于标准库中,或者至少有一个更容易识别的名称。

不幸的是,据我所知,Python没有这样的内置程序。如果您需要此功能,生成器功能可能会非常干净。

iter不太为人所知的第二种形式几乎可以实现你想要的,但不幸的是,他们让它纯粹起到了副作用,这打破了这种模式。要使用它,你需要一个类似的包装器:

def fp_iter(f, initial):
acc = initial
def wrapper():
nonlocal acc
return (acc := f(acc))
return iter(wrapper, object())
>>> i = fp_iter(lambda n: n + 1, 0)
>>> next(i)
1
>>> next(i)
2
>>> next(i)
3

在这一点上,我只会使用你的发电机。


根据它的名称,由于我使用Clojure的时间,我知道它是iterate函数。这类似于数学中的迭代,所以我认为这是一个合适的名称:

在数学中,迭代可能是指迭代函数的过程,即重复应用函数,使用一次迭代的输出作为下一次的输入。

您可以使用accumulate以某种非标准的方式实现这一点:

from itertools import accumulate, count
def turboaccumulate(f, initial):
return accumulate(count(), lambda x, y: f(x), initial=initial)

您可以使用任何无限迭代器而不是count,因为它的值会被忽略(y从不使用(。

more_itertools包含一个名为iterate的函数,该函数与您作为turboaccumulate实现的功能完全相同。

参见以下示例:

>>> from itertools import islice
>>> from more_itertools import iterate
>>> list(islice(iterate(lambda x: 2*x, 1), 10))
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

最新更新