Nur zum Spaß habe ich eine Implementierung einer Lookahead-Klasse erstellt, basierend auf dem Vorschlag von Aaron:
import itertools
class lookahead_chain(object):
def __init__(self, it):
self._it = iter(it)
def __iter__(self):
return self
def next(self):
return next(self._it)
def peek(self, default=None, _chain=itertools.chain):
it = self._it
try:
v = self._it.next()
self._it = _chain((v,), it)
return v
except StopIteration:
return default
lookahead = lookahead_chain
Damit funktioniert folgendes:
>>> t = lookahead(xrange(8))
>>> list(itertools.islice(t, 3))
[0, 1, 2]
>>> t.peek()
3
>>> list(itertools.islice(t, 3))
[3, 4, 5]
Bei dieser Implementierung ist es eine schlechte Idee, peek mehrmals hintereinander aufzurufen ...
Beim Betrachten des CPython-Quellcodes habe ich gerade einen besseren Weg gefunden, der sowohl kürzer als auch effizienter ist:
class lookahead_tee(object):
def __init__(self, it):
self._it, = itertools.tee(it, 1)
def __iter__(self):
return self._it
def peek(self, default=None):
try:
return self._it.__copy__().next()
except StopIteration:
return default
lookahead = lookahead_tee
Die Verwendung ist die gleiche wie oben, aber Sie zahlen hier keinen Preis, um Peek mehrmals hintereinander zu verwenden. Mit ein paar Zeilen mehr können Sie auch mehr als ein Element im Iterator (bis zum verfügbaren RAM) nach vorne schauen.