问题:单行检查迭代器是否产生至少一个元素?
目前,我正在这样做:
try:
    something = iterator.next()
    # ...
except StopIteration:
    # ...
但是我想要一个可以放在简单if语句中的表达式。是否有内置的东西可以使这段代码显得不太笨拙?
any()False如果iterable为空,则返回,但如果不是,则可能会遍历所有项目。我只需要检查第一项即可。
有人问我要做什么。我编写了一个函数,该函数执行SQL查询并产生其结果。有时,当我调用此函数时,我只想知道查询是否返回了任何内容,并据此做出决定。
回答 0
any如果为True,则不会超出第一个元素。万一迭代器产生一些虚假的东西,您可以编写any(True for _ in iterator)。
回答 1
在Python 2.6+中,如果名称sentinel绑定到迭代器无法产生的值,
if next(iterator, sentinel) is sentinel:
    print('iterator was empty')
如果您不知道迭代器可能产生的结果,请使用以下命令创建自己的标记(例如,在模块顶部)
sentinel = object()否则,您可以在哨兵角色中使用您“知道”(基于应用程序考虑)迭代器可能无法产生的任何值。
回答 2
这并不是真正干净,但是它显示了一种无损地将其打包在函数中的方法:
def has_elements(iter):
  from itertools import tee
  iter, any_check = tee(iter)
  try:
    any_check.next()
    return True, iter
  except StopIteration:
    return False, iter
has_el, iter = has_elements(iter)
if has_el:
  # not empty
这并不是真正的pythonic,在特定情况下,可能会有更好(但不太通用)的解决方案,例如下一个默认解决方案。
first = next(iter, None)
if first:
  # Do something
这不是一般性的,因为None在许多可迭代对象中都可以是有效元素。
回答 3
您可以使用:
if zip([None], iterator):
    # ...
else:
    # ...
但这对于代码阅读器来说有点不解
回答 4
最好的方法是使用peekablefrom more_itertools。
from more_itertools import peekable
iterator = peekable(iterator)
if iterator:
    # Iterator is non-empty.
else:
    # Iterator is empty.
请注意,如果您保留对旧迭代器的引用,则该迭代器将变得高级。从那时起,您必须使用新的可窥视迭代器。但是,实际上,peekable期望是修改该旧迭代器的唯一代码,因此无论如何您都不应保留对旧迭代器的引用。
回答 5
关于什么:
In [1]: i=iter([])
In [2]: bool(next(i,False))
Out[2]: False
In [3]: i=iter([1])
In [4]: bool(next(i,False))
Out[4]: True
回答 6
__length_hint__ 估计-的长度list(it)-这是私有方法,但是:
x = iter( (1, 2, 3) )
help(x.__length_hint__)
      1 Help on built-in function __length_hint__:
      2 
      3 __length_hint__(...)
      4     Private method returning an estimate of len(list(it)).回答 7
这是一个过大的迭代器包装器,通常可以检查是否存在下一项(通过转换为布尔值)。当然效率很低。
class LookaheadIterator ():
    def __init__(self, iterator):
        self.__iterator = iterator
        try:
            self.__next      = next (iterator)
            self.__have_next = True
        except StopIteration:
            self.__have_next = False
    def __iter__(self):
        return self
    def next (self):
        if self.__have_next:
            result = self.__next
            try:
                self.__next      = next (self.__iterator)
                self.__have_next = True
            except StopIteration:
                self.__have_next = False
            return result
        else:
            raise StopIteration
    def __nonzero__(self):
        return self.__have_next
x = LookaheadIterator (iter ([]))
print bool (x)
print list (x)
x = LookaheadIterator (iter ([1, 2, 3]))
print bool (x)
print list (x)输出:
False
[]
True
[1, 2, 3]回答 8
有点晚了,但是…您可以将迭代器变成一个列表,然后使用该列表:
# Create a list of objects but runs out the iterator.
l = [_ for _ in iterator]
# If the list is not empty then the iterator had elements; else it was empty.
if l :
    pass # Use the elements of the list (i.e. from the iterator)
else :
    pass # Iterator was empty, thus list is empty.
