How do I know if a generator is empty from the start?

Solution 1:

Suggestion:

def peek(iterable):
    try:
        first = next(iterable)
    except StopIteration:
        return None
    return first, itertools.chain([first], iterable)

Usage:

res = peek(mysequence)
if res is None:
    # sequence is empty.  Do stuff.
else:
    first, mysequence = res
    # Do something with first, maybe?
    # Then iterate over the sequence:
    for element in mysequence:
        # etc.

Solution 2:

The simple answer to your question: no, there is no simple way. There are a whole lot of work-arounds.

There really shouldn't be a simple way, because of what generators are: a way to output a sequence of values without holding the sequence in memory. So there's no backward traversal.

You could write a has_next function or maybe even slap it on to a generator as a method with a fancy decorator if you wanted to.

Solution 3:

A simple way is to use the optional parameter for next() which is used if the generator is exhausted (or empty). For example:

_exhausted  = object()

if next(some_generator, _exhausted) is _exhausted:
    print('generator is empty')

Solution 4:

next(generator, None) is not None

Or replace None but whatever value you know it's not in your generator.

Edit: Yes, this will skip 1 item in the generator. Often, however, I check whether a generator is empty only for validation purposes, then don't really use it. Or otherwise I do something like:

def foo(self):
    if next(self.my_generator(), None) is None:
        raise Exception("Not initiated")

    for x in self.my_generator():
        ...

That is, this works if your generator comes from a function, as in generator().