【问题标题】:python generator endless stream without using yieldpython生成器无限流而不使用yield
【发布时间】:2013-12-13 11:11:24
【问题描述】:

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

我想出了什么:

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

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

还请注意,在以前的前。我被要求使用产量。没有问题:

while True:
    yield x
    x = f(x)

这很好用。但现在.. 不知道如何做到这一点

【问题讨论】:

  • 这些限制是怎么回事?看起来相当人工?
  • 哇……给你这个任务的人应该重新考虑一下……在我看来,这是教人们以错误的方式完成任务的练习 /i>
  • @NPE 这也是一行。 :(
  • 是的,我之前的任务是用产量做的。生病编辑我的帖子
  • 嗯,它对产量很好。

标签: python generator


【解决方案1】:

在 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

【讨论】:

  • 我认为函数参数仅在 3.3 中出现。
  • @DSM:没错,谢谢! (顺便说一句,我很喜欢你回答中的叙述。)
  • 这很好用!还要感谢所有帮助过的人!
【解决方案2】:

我认为这可行:

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

为了便于阅读,我将它分成几行,但它本质上是 1 行。

没有任何导入的版本

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

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,他们可能会失败。最后一个版本修复了这个错误。

【讨论】:

  • 我在想可变的默认参数状态破解。
  • @DSM -- 是的,这也可以。实际上,我通过返回具有可变状态的 lambda 函数的返回值来解决状态性问题 :)
  • FWIW,我认为这是我写过的最模糊的 python 代码......谢谢教授。
  • @JonClements -- 我明白了! :)。没有进口:)。
  • 向 Bob 借用(我相信)- 它应该有一个免责声明,例如:我可以看到它,你能看到 ̲͚̖͔̙î̩́t̲͎̩̱͔́̋̀ 这是美丽的,他最终扼杀了人类的谎言 ALL IS LOŚ͖̩͇̗̪̏̈́T所有我失去了小便他来他来他是我的脸,我的脸上的脸ᵒᵒh上帝别无nono̼oonθstop the *̶̶͑̾̾͑̾̾g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨeəs͎a̧͈͖r̽̾̈͒͑enotrè̑ͧ̌aͨləzaəlgə是̘̝̙̘̝̙ͤ̾̆ͤ̾̆͠p̯͍̭o̚ N̐Y̡H̸̡̪̯ͨ͊̽̅̾ȩ̸̡̬̩̪̯̾͛ͪ̈ͨ͊̽̅̾͘ȩ̶̷̧̨̬̩̹̭̯̙̝͖̾͛ͪ̈ͧ̾ͬͭ̏ͥͮͮ͘͟͏̮̪̝͍s̨̨̨̨̨̥̫͎̭̥̫͎̭̥̫͎̭̥̫͎̭̥̫͎̭ͯ̿̔ͯ̿̔ͯ̿̔ͯ̿̔ͯ̿̔ͮ͏̮̪̝͍>
【解决方案3】:

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

【讨论】:

  • 是的,我也在考虑使用 itertools,但似乎唯一能解决问题的是 imap?
  • 我稍微误读了这个问题,正在考虑count。这不会满足您的需求,尽管您可以将某些东西从itertools...
猜你喜欢
  • 2020-04-07
  • 2021-01-27
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 2019-07-20
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
相关资源
最近更新 更多