python generator with check for empty condition

前端 未结 2 1285
孤城傲影
孤城傲影 2021-02-13 21:53

python generators are good replacements for lists in most cases expect where I would like to check for empty condition which is not possible with plain generators. I am trying t

相关标签:
2条回答
  • 2021-02-13 22:39

    Use itertools.tee to implement the nonzero test, and simply cache it on creation:

    from itertools import tee
    
    class NonZeroIterable(object):
        def __init__(self, iterable):
            self.__iterable, test = tee(iter(iterable))
            try:
                test.next()
                self.__nonzero = True
            except StopIteration:
                self.__nonzero = False                 
    
        def __nonzero__(self):
            return self.__nonzero
    
        def __iter__(self):
            return self.__iterable
    

    Little demo:

    >>> nz = NonZeroIterable('foobar')
    >>> if nz: print list(nz)
    ... 
    ['f', 'o', 'o', 'b', 'a', 'r']
    >>> nz2 = NonZeroIterable([])
    >>> if not nz2: print 'empty'
    ... 
    empty
    

    This version of the NonZeroIterable caches the flag; it thus only tells you if the iterator was non-empty at the start. If you need to be able to test the iterable at other points in it's lifecycle, use Sven's version instead; there the __nonzero__ flag will tell you after every iteration if there are more items to come still.

    Side note on your example

    Your sample code is way too simple and not a good argument for your usecase; you first test for non-emptyness (which potentially iterates over the input list to seach for an odd number) but then exhaust the whole iterator anyway. The following code would be just as efficient and wouldn't require you to invent ways to break python idioms:

    def print_odd(odd_nums):
        odd_nums = list(odd_nums)
        if odd_nums:
            print "odd numbers found", odd_nums
        else:
            print "No odd numbers found"
    
    0 讨论(0)
  • 2021-02-13 22:55

    I would not usually implement this kind of generator. There is an idiomatic way how to test if a iterator it is exhausted:

    try:
        next_item = next(it)
    except StopIteration:
        # exhausted, handle this case
    

    Substituting this EAFP idiom by some project-specific LBYL idiom seems confusing and not beneficial at all.

    That said, here is how I would implement this if I really wanted to:

    class MyIterator(object):
        def __init__(self, iterable):
            self._iterable = iter(iterable)
            self._exhausted = False
            self._cache_next_item()
        def _cache_next_item(self):
            try:
                self._next_item = next(self._iterable)
            except StopIteration:
                self._exhausted = True
        def __iter__(self):
            return self
        def next(self):
            if self._exhausted:
                raise StopIteration
            next_item = self._next_item
            self._cache_next_item()
            return next_item
        def __nonzero__(self):
            return not self._exhausted
    
    0 讨论(0)
提交回复
热议问题