Python 生成器截止

4 投票
6 回答
7536 浏览
提问于 2025-04-17 14:28

我有一个生成器,它会不断生成一些数字,这些数字是根据特定的公式计算出来的。为了方便讨论,假设这个公式是这样的:

# this is not the actual generator, just an example
def Generate():
    i = 0
    while 1:
        yield i
        i+=1       

接下来,我想从这个生成器中获取一些数字,这些数字要低于某个特定的阈值。我在想有没有一种更“pythonic”的方法来实现这个目标。我不想修改这个公式的定义。我知道可以用一个while循环来判断数字是否低于阈值,但我在想有没有更好的方法。我试过这样做,但很快就发现这样做不行。

l = [x for x in Generate() x<10000] # will go on infinitely

所以,有没有正确的方法来做到这一点呢?

谢谢

6 个回答

0

itertools.takewhile 这个函数会一直工作,直到遇到一个不符合条件的项为止。如果你想从一个可能顺序不固定的可迭代对象中返回所有值,我建议在 Python 2.x 中使用 itertools.ifilter,就像下面这样:

from itertools import ifilter
f = ifilter(lambda x: x < 400, gen())
f.next()

这个方法成功地过滤了一个生成器,产生了介于 0 到 400 之间的随机整数,正如我们所希望的那样。

顺便提一下,itertools.ifilter 在 Python 3.x 中已经被弃用,取而代之的是内置的 filter(),它在迭代时的语法稍有不同。

f = filter(lambda x: x < 400, gen())
next(f)
1

把你的生成器放在另一个生成器里面:

def no_more_than(limit):
    def limiter(gen):
        for item in gen:
            if item > limit:
                break
            yield item
    return limiter

def fib():
    a,b = 1,1
    while 1:
        yield a
        a,b = b,a+b


cutoff_at_100 = no_more_than(100)
print list(cutoff_at_100(fib()))

输出结果:

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
13

这是一个关于如何使用itertools来创建另一个迭代器的解决方案:

from itertools import takewhile
l = takewhile(lambda x: x < 10000, generate())

如果你确定想要一个列表,可以把它放在list()里面:

l = list(takewhile(lambda x: x < 10000, generate()))

或者,如果你想要一个列表,并且喜欢自己动手发明东西:

l = []
for x in generate():
    if x < 10000:
        l.append(x)
    else:
        break

撰写回答