单线程来检查一个迭代器是否至less产生一个元素?

目前我正在这样做:

try: something = iterator.next() # ... except StopIteration: # ... 

但我想要一个expression式,我可以放在一个简单的if语句中。 有什么内置的,这将使这个代码看起来不那么笨拙?

如果一个iterable是空的,则any()返回False ,但如果不是,则它将会遍历所有的项目。 我只需要检查第一个项目。


有人问我在做什么。 我已经写了一个函数,执行一个SQL查询并产生结果。 有时当我调用这个函数时,我只想知道查询是否返回任何内容,并根据这个做出决定。

如果它是真的, any不会超出第一个元素。 如果迭代器产生一些错误,你可以写any(True for _ in iterator)

在Python 2.6+中,如果名字sentinel绑定到迭代器不可能产生的值,

 if next(iterator, sentinel) is sentinel: print('iterator was empty') 

如果您不知道迭代器可能会产生什么结果,请使用自己的定点(例如,在模块的顶部)

 sentinel = object() 

否则,您可以在标记angular色中使用您“知道”的任何值(基于应用程序考虑)迭代器不可能产生的值。

这并不是很干净,但它展示了一种无损地将其打包成函数的方法:

 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,对于特定的情况,可能有更好的(但不太一般的)解决scheme,就像下一个默认的那样。

 first = next(iter, None) if first: # Do something 

这不是一般的,因为在许多迭代中None都不是一个有效的元素。

您可以使用:

 if zip([None], iterator): # ... else: # ... 

但对代码阅读器来说这是有点不合理的

__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)). 

这是一个过度的迭代器包装,通常允许检查是否有下一个项目(通过转换为布尔)。 当然相当低效。

 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] 

有点晚了,但是…你可以把迭代器变成一个列表,然后使用该列表:

 # 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 (ie from the iterator) else : pass # Iterator was empty, thus list is empty.