On 9/29/2016 12:36 PM, MRAB wrote:
On 2016-09-29 16:56, Steve D'Aprano wrote:
On Thu, 29 Sep 2016 09:53 pm, MRAB wrote:

What if an _exhausted_ iterator was falsey?

Logic is about binary distinctions, rather than about 'truth'. For non-buggy iterator it, the useful binary distinction is whether next(it) returns an object, the truthy action, or raises StopIteration, the falsey action. The for loop machinery converts this binary action distinction into another binary action distinction: execute the suite and call next again versus proceed to the else clause if there is one or do nothing. In other words, for loops indeed treat an exhausted iterator as falsey.

The problem is that in general you can't tell if an iterator is exhausted
until you attempt to advance it. So even if bool(iterator) returns True,
the call to next() may raise StopIteration:

[snip]

By "exhausted" I meant "has previously raised StopIteration".

The iterator protocol could have required that iterators have 'self._bval = True' in .__init__, method 'def __bool__(self): return self._bval, and 'self._bval = False' in .__next__ just prior to 'raise StopIteration'.

However, the iterator protocol is intentionally as simple as possible and the extra baggage would nearly always be useless. If you use a non-iterator iterable in a for statement, the temporary iterator is discarded as soon as it raises StopIteration. If you pass an iterator to a function that iterates, you likely created it on the fly as an expression, and it will be discarded when the function returns. If you do have a reference, you can (and perhaps should) delete it after the function returns.

Still, if one has a specialized use-case for iterables with the extra baggage, one can create them as instances of the following wrapper.

class BoolIter:
    def __init__(self, iterable):
        self._it = iter(iterable)
        self._bval = True
    def __iter__(self):
        return self
    def __bool__(self):
        return self._bval
    def __next__(self):
        try:
            return next(self._it)
        except StopIteration:
            self._bval = False
            raise

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to