具有if条件的生成器上的python list comprehension

时间:2018-02-12 06:56:36

标签: python python-2.7

我正在尝试使用生成器上的if条件执行列表理解,但代码卡在for循环中。

import time
def gen():
    a = 0
    b = 1
    while True:
        a += 1
        b += 1
        yield a, b
    init_time = time.time() 
    m = [{'a': x, 'b': y} for x, y in gen() if time.time() - init_time < 3]

我意识到这是因为gen()将无限返回,并且为了继续执行直到gen()可迭代,还有另一种方法吗?

1 个答案:

答案 0 :(得分:1)

列表推导中的if条件不是停止条件,它是过滤器。如上所述,3秒后它将简单地开始忽略来自发生器的对,并且永远不会返回它到目前为止所做的列表。

另一个问题是列表理解当前在生成器内部,(在非常特定的情况下除外)不是如何使用生成器的列表推导。列表推导迭代生成器生成的对象,与其定义无关。

最后,您的生成器无限。虽然无限生成器是完全有效且非常有用的,但它们不能传递给列表推导,因为列表推导要消耗整个生成器,根据定义,无法使用无限生成器。然而,人们可以编写一个有限的发电机来适应无限的发电机,当达到一个条件时停止。 itertools.islice是标准库中这种包装器的一个示例,但您可以轻松编写自己的包装器。基于时间的包装器可能如下所示:

def iter_until(tm, iterable):
    t0 = time.time()
    for val in iterable:
        yield val
        if time.time() - t0 > tm:
            break

这个包装器可以很容易地与原始无限生成器结合使用,并在列表比较中使用:

def gen():
    a = 0
    b = 1
    while True:
        a += 1
        b += 1
        yield a, b

m = [{'a': x, 'b': y} for x, y in iter_until(3, gen())]