带有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列表理解的主要内容,如果未能解决你的问题,请参考以下文章

带有内容的Python深度getsizeof列表?

python基础--条件判断循环语句与列表解析,生成器

通过python中的if条件附加列表

Python 列表解析

python列表生成式列表推导式

python条件判断