是否有一种简单的方法来测试生成器是否没有项目,比如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()
其他回答
如果你在使用生成器之前需要知道,那么不,没有简单的方法。如果你可以等到你使用生成器之后,有一个简单的方法:
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()
下面是一个包装生成器的简单装饰器,因此如果为空,它将返回None。如果您的代码需要知道生成器在循环遍历之前是否会生成任何东西,那么这可能很有用。
def generator_or_none(func):
"""Wrap a generator function, returning None if it's empty. """
def inner(*args, **kwargs):
# peek at the first item; return None if it doesn't exist
try:
next(func(*args, **kwargs))
except StopIteration:
return None
# return original generator otherwise first item will be missing
return func(*args, **kwargs)
return inner
用法:
import random
@generator_or_none
def random_length_generator():
for i in range(random.randint(0, 10)):
yield i
gen = random_length_generator()
if gen is None:
print('Generator is empty')
一个有用的例子是在模板代码中—即jinj2
{% if content_generator %}
<section>
<h4>Section title</h4>
{% for item in content_generator %}
{{ item }}
{% endfor %
</section>
{% endif %}
在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)
对你的问题的简单回答是:不,没有简单的方法。有很多变通办法。
不应该有一种简单的方法,因为生成器是一种输出值序列而不将序列保存在内存中的方法。所以没有向后遍历。
你可以写一个has_next函数,或者甚至可以把它作为一个带有花哨装饰器的方法放在生成器上。
我意识到这篇文章已经5年了,但我在寻找一种惯用的方法时发现了它,并没有看到我的解决方案发布出来。所以为了子孙后代:
import itertools
def get_generator():
"""
Returns (bool, generator) where bool is true iff the generator is not empty.
"""
gen = (i for i in [0, 1, 2, 3, 4])
a, b = itertools.tee(gen)
try:
a.next()
except StopIteration:
return (False, b)
return (True, b)
当然,我相信许多评论员会指出,这很俗气,而且只在某些有限的情况下有效(例如,生成器没有副作用)。YMMV。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录