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


当前回答

在Mark Ransom的提示下,这里有一个类,你可以使用它来包装任何迭代器,这样你就可以提前查看,将值推回流并检查是否为空。这是一个简单的想法和简单的实现,我发现在过去非常方便。

class Pushable:

    def __init__(self, iter):
        self.source = iter
        self.stored = []

    def __iter__(self):
        return self

    def __bool__(self):
        if self.stored:
            return True
        try:
            self.stored.append(next(self.source))
        except StopIteration:
            return False
        return True

    def push(self, value):
        self.stored.append(value)

    def peek(self):
        if self.stored:
            return self.stored[-1]
        value = next(self.source)
        self.stored.append(value)
        return value

    def __next__(self):
        if self.stored:
            return self.stored.pop()
        return next(self.source)

其他回答

恕我直言,最好的办法是避免特殊测试。大多数时候,使用生成器是一种测试:

thing_generated = False

# Nothing is lost here. if nothing is generated, 
# the for block is not executed. Often, that's the only check
# you need to do. This can be done in the course of doing
# the work you wanted to do anyway on the generated output.
for thing in my_generator():
    thing_generated = True
    do_work(thing)

如果这还不够好,您仍然可以执行显式测试。此时,thing将包含最后生成的值。如果没有生成任何内容,它将是未定义的—除非您已经定义了该变量。你可以检查东西的价值,但那有点不可靠。相反,只需在块内设置一个标志,然后检查它:

if not thing_generated:
    print "Avast, ye scurvy dog!"

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

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

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

简单地用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

如果你在使用生成器之前需要知道,那么不,没有简单的方法。如果你可以等到你使用生成器之后,有一个简单的方法:

was_empty = True

for some_item in some_generator:
    was_empty = False
    do_something_with(some_item)

if was_empty:
    handle_already_empty_generator_case()

这是一个古老的问题,但之前没有人提出过,下面是这个问题:

for _ in generator:
    break
else:
    print('Empty')

你可以在这里阅读更多