【问题标题】:iterate infinite generator until condition is met迭代无限生成器直到满足条件
【发布时间】:2018-04-26 15:11:14
【问题描述】:

我在理解 python 中的生成器时遇到了一些麻烦。假设我有以下简单的生成器:

def test_gen():
    yield 1
    yield 2
    yield 5
    yield 8
    yield 12

这只会产生一些数字。假设我想继续从生成器打印值,直到值超过 10。我的第一次尝试只是

gen = test_gen()
for i in gen:
    while i > 10:
        print(i)

但这只会永远打印1。我发现这样做

gen = test_gen()
for i in gen:
    if i > 10:
        print(i)

按预期工作,因为它只是遍历生成器中的每个值,直到引发StopIteration。然后我遇到了一个无限生成器的问题,比如这个生成素数的生成器:

def prime_gen():
    D = dict()
    n = 2
    while True:
        if n not in D:
            yield n
            D[n*n] = [n]
        else:
            for p in D[n]:
                D.setdefault(p + n, []).append(p)
            del D[n]
        n += 1

如果我做类似的事情

primes = prime_gen()
for p in primes:
    if p < 100:
        print(p)

然后它将打印到 p 的所有内容,但随后挂断。我认为它被挂断了,因为它试图检查primes 生成的每个值,这将永远持续下去。迭代无限生成器直到满足这样的条件的正确方法是什么?我发现的唯一方法是做

primes = prime_gen()
for p in primes:
    if p < 100:
        print(p)
    else:
        break

但我觉得有一种更 Pythonic 的方式。

【问题讨论】:

  • while i &gt; 10: print(i) 应该以不同的方式工作吗?
  • if &lt;something&gt;: do_something() else: break 是非常pythonic和正常的。
  • 看来你的建议对我来说是正确的答案

标签: python generator


【解决方案1】:

itertools.takewhile()

for i in itertools.takewhile(lambda x: x < 100, primes):
  print(i)

【讨论】:

  • 看来它的作用与我在问题中的建议相同。有趣的是,当我使用%timeit 对其进行测试时,itertools.takewhile() 比我的问题中的方法要慢一些。也许没有更好的方法。
【解决方案2】:

您的break 方法非常Pythonic,但我会考虑包装生成器:

for p in (i if i < 100 else StopIteration for i in primes):
    print(p)

【讨论】:

  • 如果你这样做,它会挂断,因为它仍在尝试检查生成的每个值。
  • @greenthumbtack 糟糕,请重试
猜你喜欢
  • 1970-01-01
  • 2020-10-06
  • 2021-11-26
  • 2020-06-16
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2022-01-13
  • 2016-11-16
相关资源
最近更新 更多