8

我需要一个 Python 函数iterate(f, x)来创建一个返回值 x、f(x)、f(f(x))、f(f(f(x))) 等的迭代器(例如Clojure 的iterate)。首先,我想知道:这是否已经存在于标准库中的某个地方而我只是想念它?当然,使用生成器很容易实现:

def iterate(f, x):
    while True:
        yield x
        x = f(x)

只是出于好奇:在 Python 中是否有更实用的方法来执行此操作,例如使用一些 itertools 或 functools 魔术?

在 Python 3.3 中,这可以工作

def iterate(f, x):
    return accumulate(repeat(x), lambda acc, _ : f(acc))

但对我来说似乎是一种虐待。我可以做得更好吗?

4

2 回答 2

6

itertools 中似乎没有任何东西可以满足您的需求,但是 itertools 是一个很深的宝箱,所以我可能错过了一些东西。

您的生成器代码看起来很棒。我不知道为什么你会用累积来写它,除非你正在玩一个荒谬的代码高尔夫游戏,或者你试图打动 Haskell 势利小人。编写函数,使其可读、可理解和可维护。无需过于聪明。

于 2013-03-26T12:09:47.343 回答
3

您可以使用变形(或展开)来简化 的定义iterate,并仅使用一个起始值。这是我曾经使用过的一个实现,基于一篇非常著名的论文

def ana(build, predicate):
    def h(x):
        if predicate(x):
            return
        else:
            a, b = build(x)
            yield a
            for i in h(b):
                yield i
            # with newer syntax: 
            # yield from h(b)
    return h

iterate使用then实现ana如下所示:

def iterate(f, x):
    return ana(lambda x: (x, f(x)), lambda _: False)(x)

没有 itertools,但是……我同意这不是最易读的变体。事实上,它相当神秘。


更新:有一个更简单的版本,甚至看起来相当不错。它取自这里

def unfold(f, x):
    while True:
        w, x = f(x)
        yield w

这给了你:

def iterate(f, x):
    return unfold(lambda y: (y, f(y)), x)
于 2013-03-27T17:36:56.057 回答