是否有一种简单的方法来测试生成器是否没有项目,比如peek, hasNext, isEmpty之类的?
当前回答
一种简单的方法是使用next()的可选参数,如果生成器耗尽(或为空),则使用该参数。例如:
_exhausted = object()
if next(some_generator, _exhausted) is _exhausted:
print('generator is empty')
其他回答
使用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
此函数返回的迭代器将等效于作为参数传入的原始迭代器。
刚刚读到这篇文章,意识到缺少一个非常简单易懂的答案:
def is_empty(generator):
for item in generator:
return False
return True
如果我们不打算使用任何项,那么我们需要将第一项重新注入生成器:
def is_empty_no_side_effects(generator):
try:
item = next(generator)
def my_generator():
yield item
yield from generator
return my_generator(), False
except StopIteration:
return (_ for _ in []), True
例子:
>>> g=(i for i in [])
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
True
>>> g=(i for i in range(10))
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
False
>>> list(g)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
恕我直言,最好的办法是避免特殊测试。大多数时候,使用生成器是一种测试:
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!"
Bool (generator)将返回正确的结果
如果你在使用生成器之前需要知道,那么不,没有简单的方法。如果你可以等到你使用生成器之后,有一个简单的方法:
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()