使用itertools进行递归函数应用

时间:2013-03-26 12:05:20

标签: python functional-programming iterator generator itertools

我需要一个Python函数iterate(f, x),它创建一个迭代器,返回值x,f(x),f(f(x)),f(f(f(x)))等(如,例如,Clojure's 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))

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

2 个答案:

答案 0 :(得分:5)

在itertools中似乎没有什么可以做你想要的东西,但是itertools是一个很深的宝库,所以我可能错过了一些东西。

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

答案 1 :(得分:3)

您可以使用anamorphism(或展开)来简化iterate的定义,并仅使用一个起始值。这是我曾经使用的一个实现,基于一个非常着名的paper

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实施ana,然后如下所示:

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

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


更新:有一个更简单的版本,甚至看起来很不错。它来自here

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

这会给你:

def iterate(f, x):
    return unfold(lambda y: (y, f(y)), x)