One-liner to check whether an iterator yields at least one element?

后端 未结 9 1827
野的像风
野的像风 2020-12-05 01:45

Currently I\'m doing this:

try:
    something = iterator.next()
    # ...
except StopIteration:
    # ...

But I would like an expression th

相关标签:
9条回答
  • 2020-12-05 01:59

    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).

    0 讨论(0)
  • 2020-12-05 02:00

    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.

    0 讨论(0)
  • 2020-12-05 02:00

    This is an overkill iterator wrapper that generally allows to check whether there's a next item (via conversion to boolean). Of course pretty inefficient.

    class LookaheadIterator ():
    
        def __init__(self, iterator):
            self.__iterator = iterator
            try:
                self.__next      = next (iterator)
                self.__have_next = True
            except StopIteration:
                self.__have_next = False
    
        def __iter__(self):
            return self
    
        def next (self):
            if self.__have_next:
                result = self.__next
                try:
                    self.__next      = next (self.__iterator)
                    self.__have_next = True
                except StopIteration:
                    self.__have_next = False
    
                return result
    
            else:
                raise StopIteration
    
        def __nonzero__(self):
            return self.__have_next
    
    x = LookaheadIterator (iter ([]))
    print bool (x)
    print list (x)
    
    x = LookaheadIterator (iter ([1, 2, 3]))
    print bool (x)
    print list (x)
    

    Output:

    False
    []
    True
    [1, 2, 3]
    
    0 讨论(0)
  • 2020-12-05 02:05

    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.

    0 讨论(0)
  • 2020-12-05 02:11

    you can use:

    if zip([None], iterator):
        # ...
    else:
        # ...
    

    but it's a bit nonexplanatory for the code reader

    0 讨论(0)
  • 2020-12-05 02:20

    A little late, but... You could turn the iterator into a list and then work with that list:

    # Create a list of objects but runs out the iterator.
    l = [_ for _ in iterator]
    
    # If the list is not empty then the iterator had elements; else it was empty.
    if l :
        pass # Use the elements of the list (i.e. from the iterator)
    else :
        pass # Iterator was empty, thus list is empty.
    
    0 讨论(0)
提交回复
热议问题