带有if条件的生成器上的python列表理解
Posted
技术标签:
【中文标题】带有if条件的生成器上的python列表理解【英文标题】:python list comprehension on generator with if condition 【发布时间】:2018-02-12 06:56:35 【问题描述】:我正在尝试在生成器上使用 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()
将无限返回并且for 将继续执行直到gen()
是可迭代的,还有其他方法吗?
【问题讨论】:
你希望它如何结束?终止条件是什么? 您的代码格式是否正确?如果您将最后两行取消缩进,它将起作用。 我希望在 3 秒内为生成器生成的所有值创建一个 dict 列表 @DYZ 它不起作用,因为生成器仍然是无限的。它只会停止将值添加到列表中,但永远不会返回它到目前为止创建的列表。 @AamirShaikh 然后你应该在生成器中移动计时器并使用它来终止循环 【参考方案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())]
【讨论】:
g = gen();而 time.time() -time @AamirShaikh 答案提供了在惯用 Python 中执行此操作的代码 - 请参阅iter_until
中的 for
循环。以上是关于带有if条件的生成器上的python列表理解的主要内容,如果未能解决你的问题,请参考以下文章