cpython/Tools/c-analyzer/c_common/iterutil.py

def peek_and_iter(items):
    if not items:
        return None, None
    items = iter(items)
    try:
        peeked = next(items)
    except StopIteration:
        return None, None
    def chain():
        yield peeked
        yield from items
    return chain(), peeked


def iter_many(items, onempty=None):
    if not items:
        if onempty is None:
            return
        if not callable(onempty):
            raise onEmpty
        items = onempty(items)
        yield from iter_many(items, onempty=None)
        return
    items = iter(items)
    try:
        first = next(items)
    except StopIteration:
        if onempty is None:
            return
        if not callable(onempty):
            raise onEmpty
        items = onempty(items)
        yield from iter_many(items, onempty=None)
    else:
        try:
            second = next(items)
        except StopIteration:
            yield first, False
            return
        else:
            yield first, True
            yield second, True
        for item in items:
            yield item, True