3

Follow up from this question. How can I modify this code to allow for rewinding of multiple lines?

class rewindable_iterator(object):
    not_started = object()

    def __init__(self, iterator):
        self._iter = iter(iterator)
        self._use_save = False
        self._save = self.not_started

    def __iter__(self):
        return self

    def next(self):
        if self._use_save:
            self._use_save = False
        else:
            self._save = self._iter.next()
        return self._save

    def backup(self):
        if self._use_save:
            raise RuntimeError("Tried to backup more than one step.")
        elif self._save is self.not_started:
            raise RuntimeError("Can't backup past the beginning.")
        self._use_save = True
Community
  • 1
  • 1
Pierpaolo
  • 1,721
  • 4
  • 20
  • 34
  • 2
    Use a list to save multiple iterations. You'll need some limit after which you discard the oldest when adding a new one. `backup` would need a count to back up and you could do something like take a slice and replay that. – tdelaney Nov 10 '15 at 02:05
  • 1
    @tdelaney: A `collections.deque` with a `maxlen` would work even better, allowing new lines to age off old ones automatically. – ShadowRanger Nov 10 '15 at 02:23

1 Answers1

1

This is the solution I came up with:

from collections import deque
class rewindable_iterator(object):
    not_started = object()

    def __init__(self, filename,deque_max_length=2):
        self._f=open(filename,'r')
        self._iter = iter(self._f)
        self._use_save = False
#        self._use_save2 = False
        self._save = self.not_started
        self._use_num=0
        self._deque=deque([],deque_max_length)

    def __iter__(self):
        return self
    def __enter__(self):
        return self
    def readline(self):
        return self._iter.readline()

    def __exit__(self,exc_type, exc_value, traceback):
        if exc_type is not None:
            print exc_type, exc_value, traceback
        self._f.close()

    def next(self):
        if self._use_save:
            self._use_num -= 1
            if not self._use_num:
                self._use_save = False
            return self._deque[-self._use_num-1]
        else:
            self._save = self._iter.next()
            self._deque.append(self._save)
            return self._save

    def backup(self,num=2):

        if self._use_num+num>len(self._deque):
            raise RuntimeError("Tried to backup more than the available lines")
        elif self._save is self.not_started:
            raise RuntimeError("Can't backup past the beginning.")
        self._use_save = True
        self._use_num+=num
Pierpaolo
  • 1,721
  • 4
  • 20
  • 34