any
won't go beyond the first element if it's True. In case the iterator yields something false-ish you can write any(True for _ in iterator)
.
In Python 2.6+, if name sentinel
is bound to a value which the iterator can't possibly yield,
if next(iterator, sentinel) is sentinel:
print('iterator was empty')
If you have no idea of what the iterator might possibly yield, make your own sentinel (e.g. at the top of your module) with
sentinel = object()
Otherwise, you could use, in the sentinel role, any value which you "know" (based on application considerations) that the iterator can't possibly yield.
This isn't really cleaner, but it shows a way to package it in a function losslessly:
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
This isn't really pythonic, and for particular cases, there are probably better (but less general) solutions, like the next default.
first = next(iter, None)
if first:
# Do something
This isn't general because None can be a valid element in many iterables.
The best way to do that is with a peekable
from more_itertools
.
from more_itertools import peekable
iterator = peekable(iterator)
if iterator:
# Iterator is non-empty.
else:
# Iterator is empty.
Just beware if you kept refs to the old iterator, that iterator will get advanced. You have to use the new peekable iterator from then on. Really, though, peekable expects to be the only bit of code modifying that old iterator, so you shouldn't be keeping refs to the old iterator lying around anyway.
you can use:
if zip([None], iterator):
# ...
else:
# ...
but it's a bit nonexplanatory for the code reader
What about:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With