[Python-ideas] Add lookahead iterator (peeker) to itertools
Terry Reedy
tjreedy at udel.edu
Tue Feb 26 22:57:36 CET 2013
On 2/25/2013 10:29 AM, Ron Adam wrote:
>
>
> On 02/24/2013 09:41 PM, Terry Reedy wrote:
>> class lookahead():
>> "Wrap iterator with lookahead to both peek and test exhausted"
>>
>> _NONE = object()
>> def __init__(self, iterable):
>> self._it = iter(iterable)
>> self._set_peek()
>> def __iter__(self):
>> return self
>> def __next__(self):
>> ret = self.peek
>> self._set_peek()
>> return ret
>> def _set_peek(self):
>> try:
>> self.peek = next(self._it)
>> except StopIteration:
>> self.peek = self._NONE
>> def __bool__(self):
>> return self.peek is not self._NONE
>
>>
>> def test_lookahead():
>> it = lookahead('abc')
>> while it:
>> a = it.peek
>> b = next(it)
>> print('next:', b, '; is peek:', a is b )
>>
>> test_lookahead()
Since revised.
> I think with a few small changes I would find it useful.
>
> The key feature here is that the result is pre calculated and held until
> it's needed, rather than calculated when it's asked for.
>
> You should catch any exception and hold that as well. On the next
> .next() call, it should raise the exception if there was one, or emit
> the value.
My revised version has
def _set_peek(self):
try:
self.peek = next(self._it)
except StopIteration:
self.peek = self._NONE
That could easily be changed to e
except Exception as e:
self.peek = self._NONE
self._error = e
__next would then raise self._error instead of explicitly StopIteration.
I do not especially like the redundancy of two 'exhausted' indicators
and thought of storing e as self.peek, but an iterator can legitimately
yield exception classes and instances.
I think some argument can be made that if the iterator is broken, the
exception should be raised immediately even if it means not returning
the last item. No user should be expecting anything other than
StopIteration.
> I'm not sure if using the __bool__ attribute is the best choice.
I am ;-). It hides the test for exhaustion, which could change, without
complication.
> I would prefer a .error flag, along with a .next_value attribute. It
> would make the code using it easier to follow.
Not clear to me, but a minor detail.
> it.error <-- True if next(it) will raise an exception.
> it.next_value <-- The next value, or the exception to raise.
> About it.error. If it was a concurrent version, then it.error could
> have three values.
>
> it.error == True # Will raise an exception
> it.error == False # Will not raise an exception
> it.error == None # Still calculating
>
> I wonder how this type of generator will behave with "yield from".
lookaheads are iterators, but not generators and 'yield from' requires a
generator. A generator function could recompute items to yield, but it
cannot add methods or attributes to the generator instances it will produce.
--
Terry Jan Reedy
More information about the Python-ideas
mailing list