是否有一种简单的方法来测试生成器是否没有项目,比如peek, hasNext, isEmpty之类的?


当前回答

我发现只有这个解决方案也适用于空迭代。

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    try:
        next(a)
    except StopIteration:
        return True, b
    return False, b

is_empty, generator = is_generator_empty(generator)

或者如果你不想使用异常来尝试使用

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    for item in a:
        return False, b
    return True, b

is_empty, generator = is_generator_empty(generator)

在标记的解决方案中,您不能将其用于空生成器,如

def get_empty_generator():
    while False:
        yield None 

generator = get_empty_generator()

其他回答

简单地用itertools包装生成器。Chain,在第二个可迭代对象中放入一个表示可迭代对象的结尾的东西,然后简单地检查它。

Ex:

import itertools

g = some_iterable
eog = object()
wrap_g = itertools.chain(g, [eog])

现在剩下的就是检查我们附加到可迭代对象末尾的值,当你读取它时,它将表示结束

for value in wrap_g:
    if value == eog: # DING DING! We just found the last element of the iterable
        pass # Do something

为了表达我的“2美分”,我将描述一下我的经历:

我有一个生成器,我需要用itertools切片它。分成小发电机。然后检查我的子生成器是否为空,我只是将它们转换/消耗到一个小列表中,然后检查列表是否为空。

例如:

from itertools import islice

def generator(max_yield=10):
    a = 0

    while True:
        a += 1

        if a > max_yield:
            raise StopIteration()

        yield a

tg = generator()

label = 1

while True:
    itg = list(islice(tg, 3))

    if not itg:  # <-- I check if the list is empty or not
        break

    for i in itg:
        print(f'#{label} - {i}')

    label += 1

输出:

#1 - 1
#1 - 2
#1 - 3
#2 - 4
#2 - 5
#2 - 6
#3 - 7
#3 - 8
#3 - 9
#4 - 10

也许这不是最好的方法,主要是因为它会消耗生成器,但对我来说却是可行的。

>>> gen = (i for i in [])
>>> next(gen)
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    next(gen)
StopIteration

在生成器结束时引发StopIteration,因为在您的情况下立即到达结束,因此引发异常。但通常你不应该检查下一个值是否存在。

你可以做的另一件事是:

>>> gen = (i for i in [])
>>> if not list(gen):
    print('empty generator')

对于这种显而易见的方法,我很抱歉,但最好的方法是:

for item in my_generator:
     print item

现在您已经检测到在使用生成器时它是空的。当然,如果生成器为空,项将永远不会显示。

这可能不完全适合您的代码,但这就是生成器的习惯用法:迭代,所以您可能会稍微改变您的方法,或者根本不使用生成器。

我用求和函数解出来了。请参阅下面我使用glob的示例。Iglob(返回一个生成器)。

def isEmpty():
    files = glob.iglob(search)
    if sum(1 for _ in files):
        return True
    return False

*这可能不适用于巨大的生成器,但对于较小的列表应该表现得很好