是否有一种简单的方法来测试生成器是否没有项目,比如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()

其他回答

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

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

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

使用cytoolz中的peek函数。

from cytoolz import peek
from typing import Tuple, Iterable

def is_empty_iterator(g: Iterable) -> Tuple[Iterable, bool]:
    try:
        _, g = peek(g)
        return g, False
    except StopIteration:
        return g, True

此函数返回的迭代器将等效于作为参数传入的原始迭代器。

要查看生成器是否为空,只需尝试获得下一个结果。当然,如果你还没有准备好使用这个结果,那么你必须存储它,以便以后再次返回。

下面是一个包装器类,可以添加到现有的迭代器中以添加__nonzero__测试,因此您可以通过简单的if查看生成器是否为空。它也可以变成一个装饰器。

class GenWrapper:
    def __init__(self, iter):
        self.source = iter
        self.stored = False

    def __iter__(self):
        return self

    def __nonzero__(self):
        if self.stored:
            return True
        try:
            self.value = next(self.source)
            self.stored = True
        except StopIteration:
            return False
        return True

    def __next__(self):  # use "next" (without underscores) for Python 2.x
        if self.stored:
            self.stored = False
            return self.value
        return next(self.source)

下面是你如何使用它:

with open(filename, 'r') as f:
    f = GenWrapper(f)
    if f:
        print 'Not empty'
    else:
        print 'Empty'

请注意,您可以在任何时候检查空,而不仅仅是在迭代的开始。

建议:

def peek(iterable):
    try:
        first = next(iterable)
    except StopIteration:
        return None
    return first, itertools.chain([first], iterable)

用法:

res = peek(mysequence)
if res is None:
    # sequence is empty.  Do stuff.
else:
    first, mysequence = res
    # Do something with first, maybe?
    # Then iterate over the sequence:
    for element in mysequence:
        # etc.

对你的问题的简单回答是:不,没有简单的方法。有很多变通办法。

不应该有一种简单的方法,因为生成器是一种输出值序列而不将序列保存在内存中的方法。所以没有向后遍历。

你可以写一个has_next函数,或者甚至可以把它作为一个带有花哨装饰器的方法放在生成器上。