python生成器无限流而不使用yield

时间:2013-11-27 17:09:36

标签: python generator

我试图在给定函数f和初始值x的情况下生成无穷无尽的结果流 所以第一次调用应该给出初始值,第二次调用应该给f(x),第三次调用是f(x2),而x2是f(x)的前一次结果,依此类推..

我想出了什么:

def generate(f, x): 
   return itertools.repeat(lambda x: f(x))

似乎不起作用。有任何想法吗? (我不能在我的代码中使用yield)。我也不能使用超过1行代码来解决这个问题。任何帮助将不胜感激。

还要注意前一个前任。我被要求使用收益率。没有问题:

while True:
    yield x
    x = f(x)

这很好用。但现在......没有线索如何在没有

的情况下做到这一点

3 个答案:

答案 0 :(得分:4)

在Python 3.3中,您可以使用itertools.accumulate

import itertools

def generate(f, x):
  return itertools.accumulate(itertools.repeat(x), lambda v,_:f(v))

for i, val in enumerate(generate(lambda x: 2*x, 3)):
  print(val)
  if i == 10:
    break

答案 1 :(得分:4)

我认为这有效:

import itertools as it
def g(f, x):
    return it.chain([x],(setattr(g, 'x', f(getattr(g, 'x', x))) or getattr(g, 'x') for _ in it.count()))

def f(x):
    return x + 1

gen = g(f, 1)
print next(gen)
print next(gen)
print next(gen)
print next(gen)

当然,它依赖于一些粗略的行为,我实际上为函数本身添加了一个属性以保持状态。基本上,此功能仅在您第一次调用时才起作用。之后,所有赌注都已关闭。

如果我们想放宽这个限制,我们可以使用临时命名空间。问题是,要获得临时命名空间,我们需要一个唯一的类实例(或类,但实例更清晰,只需要一组额外的括号)。为了在一行中实现这一点,我们需要创建一个新的内联函数并将其用作默认参数:

import itertools as it
def g(f, x):
    return (lambda f, x, ns=type('foo', (object,), {})(): \
        it.chain([x], 
                 (setattr(ns, 'x', f(getattr(ns, 'x', x))) or getattr(ns, 'x') 
                          for _ in it.count()))
            )(f, x)

def f(x):
    return x + 1

gen = g(f, 1)
print next(gen) == 1
print next(gen) == 2
print next(gen) == 3
print next(gen) == 4

print "first worked?"
gen2 = g(f, 2)
print next(gen2) == 2
print next(gen2) == 3
print next(gen2) == 4

为了便于阅读,我把它分成几行,但它本质上是一个单行。

没有任何导入的版本

(我认为最强大的一个)。

def g(f, x):
    return iter(lambda f=f, x=x, ns=type('foo', (object,), {'x':x}): ((getattr(ns, 'x'),setattr(ns, 'x', f(getattr(ns, 'x'))))[0]), object())

这里的一个技巧与以前一样。我们使用可变的默认参数创建一个lambda函数来保持状态。在函数内部,我们构建了一个元组。第一项是我们真正想要的,第二项是setattr函数的返回值,用于更新状态。为了摆脱itertools.chain,我们将命名空间的初始值设置为x的值,因此该类已初始化为具有起始状态。第二个技巧是我们使用iter的两个参数形式来摆脱it.count(),它仅用于创建无限可迭代之前。 iter一直调用你给它的函数作为第一个参数,直到返回值等于第二个参数。但是,由于我的第二个参数是object的实例,因此从函数返回的任何内容都不会等于它,因此我们有效地创建了无itertoolsyield的无限可迭代!想想看,我相信最后一个版本也是最强大的。以前的版本有一个错误,他们依赖于f的返回值的真实性。我认为如果f返回0,他们可能会失败。最后一个版本修复了该错误。

答案 2 :(得分:0)

我猜这是某种家庭作业或作业?因此,我要说你应该看看generator expressions。虽然我同意其他评论者认为这似乎是一种可疑的价值......