How to unget a line when reading from a file/stream iterator/generator?

Duncan Booth duncan.booth at invalid.invalid
Tue Apr 29 05:23:33 EDT 2008


George Sakkis <george.sakkis at gmail.com> wrote:

> On Apr 28, 10:10 pm, pyt... at bdurham.com wrote:
>> George,
>>
>> > Is there an elegant way to unget a line when reading from a
>> > file/stream 
> iterator/generator?
>>
>> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502304
>>
>> That's exactly what I was looking for!
>>
>> For those following this thread, the above recipe creates a generic
>> object that wraps any iterator with an 'unget' ("push") capability.
>> Clean and elegant!
>>
>> Thank you,
>> Malcolm
> 
> A small suggestion: since unget is expected to be called infrequently,
> next should better be faster for the common case instead of penalizing
> it with a try/except:
> 
>     def next(self):
>         if not self.pushed_back:
>             return self.it.next()
>         else:
>             return self.pushed_back.pop()
> 

If speed is an issue then it may be better to avoid the test altogether:

    def __init__(self, it):
        self.it = it
        self.pushed_back = []
        self.nextfn = it.next
        
    def __iter__(self):
        return self
    
    def __nonzero__(self):
        if self.pushed_back:
            return True
        
        try:
            self.pushback(self.nextfn())
        except StopIteration:
            return False
        else:
            return True

    def popfn(self):
        lst = self.pushed_back
        res = lst.pop()
        if not lst:
            self.nextfn = self.it.next
        return res
        
    def next(self):
        return self.nextfn()

    def pushback(self, item):
        self.pushed_back.append(item)
        self.nextfn = self.popfn



More information about the Python-list mailing list