单行检查迭代器是否产生至少一个元素?

Bas*_*ard 92 python iterator

目前我这样做:

try:
    something = iterator.next()
    # ...
except StopIteration:
    # ...
Run Code Online (Sandbox Code Playgroud)

但我想要一个表达式,我可以放在一个简单的if陈述中.是否有任何内置功能可以使这些代码看起来不那么笨拙?

any()False如果iterable为空,则返回,但如果不是,则可能会迭代所有项.我只需要它来检查第一项.


有人问我要做什么.我编写了一个执行SQL查询并生成结果的函数.有时当我调用此函数时,我只想知道查询是否返回任何内容并根据它做出决定.

Joc*_*zel 125

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

  • 这个解决方案的一个大问题是,如果它不是空的,你实际上不能使用迭代器返回的值,对吧? (12认同)
  • 类似地,如果你需要检查迭代器是否为空,可以使用`all(迭代器中的_为False)`将检查迭代器是否为空.(如果迭代器为空,则all返回True,否则在看到第一个False元素时停止) (11认同)
  • 笔记!这会消耗迭代器中的第一个项目,因此它丢失了,消失了,你不能再使用它了。 (2认同)
  • 您可以使用 if list(iterator) == [] 或 if not any(iterator) 来检查它是否为空,或者使用 if any(iterator) 来检查它是否包含某些内容 (2认同)

Ale*_*lli 35

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

if next(iterator, sentinel) is sentinel:
    print('iterator was empty')
Run Code Online (Sandbox Code Playgroud)

如果您不知道迭代器可能会产生什么,请创建自己的标记(例如,在模块的顶部)

sentinel = object()
Run Code Online (Sandbox Code Playgroud)

否则,您可以在sentinel角色中使用您"知道"(基于应用程序注意事项)迭代器无法产生的任何值.

  • @wasabi 请记住,对于任何虚假对象,“not”都会返回 True,例如空列表、False 和零。“is not None”更安全,而且在我看来更清晰。 (3认同)
  • 好的!对于我的用例,“if not next(iterator, None):”就足够了,因为我确信 None 不会成为项目的一部分。感谢您为我指明了正确的方向! (2认同)

Mat*_*hen 19

这不是很清晰,但它显示了一种无损地将其打包到函数中的方法:

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
Run Code Online (Sandbox Code Playgroud)

这不是真正的pythonic,对于特定情况,可能有更好(但不太通用)的解决方案,如下一个默认.

first = next(iter, None)
if first:
  # Do something
Run Code Online (Sandbox Code Playgroud)

这不是通用的,因为None可以是许多迭代中的有效元素.

  • 这个解决方案中存在巨大的内存泄漏.如果`any_check`需要前进,itertools中的`tee`将必须保留原始迭代器中的每个元素.这比将原始迭代器转换为列表更糟糕. (2认同)

eni*_*ist 7

最好的方法是使用peekablefrom more_itertools

from more_itertools import peekable
iterator = peekable(iterator)
if iterator:
    # Iterator is non-empty.
else:
    # Iterator is empty.
Run Code Online (Sandbox Code Playgroud)

请注意,如果您保留对旧迭代器的引用,则该迭代器将变得先进。从那时起,您必须使用新的 peekable 迭代器。但是,确实,peekable 期望是修改旧迭代器的唯一代码,因此无论如何您都不应该保留对旧迭代器的引用。

  • 仅供参考,“more_itertools”不在标准库中。 (6认同)

myk*_*hal 6

您可以使用:

if zip([None], iterator):
    # ...
else:
    # ...
Run Code Online (Sandbox Code Playgroud)

但对于代码阅读器来说,它有点无法解释

  • ..(你可以使用任何1项迭代而不是[无]) (2认同)

Nei*_*eil 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
Run Code Online (Sandbox Code Playgroud)

  • 有趣的一个!但是如果 next() 返回 False 因为它是真正产生的结果呢? (4认同)