2

Let us suppose we have a generator function gen(), which we do not know if it is empty or not.

If it is empty, we would like to execute a special function foo(), and otherwise we would like to execute a function over each element of the iterator bar(elem).

I can do it like this:

is_empty = True
for elem in gen():
    is_empty = False
    bar(elem)
if is_empty: foo()

But that does not feel very pythonic. Any other approach?

Jsevillamol
  • 2,425
  • 2
  • 23
  • 46
  • 1
    Your approach isn't terrible, btw. It's pythonic enough. Generally, you shouldn't care whether a iterator is empty, or rather, this should be known by the results of iterating over it. – juanpa.arrivillaga Dec 24 '18 at 17:44

2 Answers2

2

You can't tell directly whether a generator is empty. This is by design. A key principle behind generators is they do not hold in memory all items of a generated sequence.

But you can do something like this:

from itertools import chain

def check_first_and_iterate(iterable):
    try:
        first = next(iterable)
        for item in chain([first], item):
            bar(item)
    except StopIteration:
        foo()

check_first_and_iterate(iterable)
jpp
  • 159,742
  • 34
  • 281
  • 339
2

There's the peek function:

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

res = peek(gen())
if not res:
    foo()
else:
    for elem in res[1]:
        bar(elem)

You will still need to peek into the generator, but you can do it cleanly.

cs95
  • 379,657
  • 97
  • 704
  • 746