简体   繁体   English

带有if条件的生成器上的python列表理解

[英]python list comprehension on generator with if condition

I am trying to perform list comprehension with if condition on a generator, but the code gets stuck in for loop. 我试图用生成器上的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]

I realised this is because gen() will return infinitely and for will continue to execute till gen() is iterable can there be another way? 我意识到这是因为gen()将无限返回,并且将继续执行直到gen()可迭代,还有其他方法吗?

The if condition in a list comprehension is not a stop condition, it's a filter . 列表推导中的if条件不是停止条件,而是一个filter As written, after 3 seconds it will simply start ignoring the pairs coming from the generator, and will never return the list it's made so far. 如所写,3秒钟后,它将仅开始忽略来自生成器的配对,并且永远不会返回到目前为止的列表。

Another problem is that the list comprehension is currently inside the generator, which is (except in very specific circumstances) not how one uses list comprehensions with generators. 另一个问题是列表推导当前位于生成器内部,这(在非常特殊的情况下除外)不是生成器使用列表推导的方式。 A list comprehension iterates over the objects produced by the generator independent of its definition. 列表理解对生成器生成的对象进行迭代,而与生成器的定义无关。

Finally, your generator is infinite . 最后,您的生成器是infinite While infinite generators are perfectly valid and very useful, they cannot be passed to list comprehensions, because the list comprehension wants to consume the entire generator, which is by definition impossible with an infinite one. 尽管无限生成器是完全有效且非常有用的,但它们无法传递给列表推导,因为列表推导要消耗整个生成器,按照定义,无限生成器是不可能的。 However, one can write a finite generator that adapts an infinite one, stopping when a condition is reached. 但是,可以编写适应无限生成器的有限生成器,并在达到条件时停止。 itertools.islice is an example of such a wrapper in a standard library, but you can easily write your own. itertools.islice是标准库中此类包装器的示例,但是您可以轻松编写自己的包装器。 A time-based wrapper might look like this: 基于时间的包装器可能如下所示:

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

This wrapper can be easily combined with the original infinite generator and used in list comparehensions: 此包装器可以轻松地与原始无限生成器组合,并用于列表比较:

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())]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM