我正在尝试使用生成器上的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()
可迭代,还有另一种方法吗?
答案 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())]