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

Discussion in 'Python' started by python@bdurham.com, Apr 28, 2008.

  1. Guest

    Is there an elegant way to unget a line when reading from a file/stream
    iterator/generator?

    By "unget" I mean a way to push back a line into the source stream and
    backtrack the iterator/generator one step?

    The only alternative I can see is to put my line reading in a while-True
    loop (vs. a for-loop) that manually calls my file/stream
    iterator/generator's .next() method while manually handling the
    StopIteration exception. Doesn't sound too elegant.

    Is there a Pythonic design pattern/best practice that I can apply here?

    Thank you,
    Malcolm
    , Apr 28, 2008
    #1
    1. Advertising

  2. Re: How to unget a line when reading from a file/stream iterator/generator?

    writes:

    > Is there an elegant way to unget a line when reading from a file/stream
    > iterator/generator?
    >
    > By "unget" I mean a way to push back a line into the source stream and
    > backtrack the iterator/generator one step?
    >
    > The only alternative I can see is to put my line reading in a while-True
    > loop (vs. a for-loop) that manually calls my file/stream
    > iterator/generator's .next() method while manually handling the
    > StopIteration exception. Doesn't sound too elegant.
    >
    > Is there a Pythonic design pattern/best practice that I can apply here?


    It seems to me that the answer depends on what you do with your
    unget'ed line (i.e. there is no included general purpose 'unget'
    replacement). If you provided some (pseudo-)code, someone might be
    able to find an elegant way to perform the task without the need to
    push back an element into an iterator.

    As a last resort, you could always wrap your iterator into a some
    'Backtrackable' class.

    class Backtrackable(object):
    def __init__(self, iterator):
    self.iterator = iter(iterator)
    self._back = False
    self._last = None
    def __iter__(self):
    return self
    def next(self):
    if self._back:
    next = self._last
    else:
    self._last = next = self.iterator.next()
    self._back = False
    return next
    def back(self):
    if self._back:
    raise('Cannot backtrack twice')
    self._back = True

    >>> b = Backtrackable([1,2,3])
    >>> b.next()

    1
    >>> b.next()

    2
    >>> b.back()
    >>> b.next()

    2
    >>> b.next()

    3
    Arnaud Delobelle, Apr 28, 2008
    #2
    1. Advertising

  3. On Apr 28, 2:07 pm, wrote:
    > Is there an elegant way to unget a line when reading from a file/stream
    > iterator/generator?
    >
    > By "unget" I mean a way to push back a line into the source stream and
    > backtrack the iterator/generator one step?
    >
    > The only alternative I can see is to put my line reading in a while-True
    > loop (vs. a for-loop) that manually calls my file/stream
    > iterator/generator's .next() method while manually handling the
    > StopIteration exception. Doesn't sound too elegant.
    >
    > Is there a Pythonic design pattern/best practice that I can apply here?
    >
    > Thank you,
    > Malcolm


    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502304

    HTH,
    George
    George Sakkis, Apr 28, 2008
    #3
  4. Guest

    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
    , Apr 29, 2008
    #4
  5. On Apr 28, 10:10 pm, 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()

    George
    George Sakkis, Apr 29, 2008
    #5
  6. Guest

    Duncan,

    > If speed is an issue then it may be better to avoid the test altogether ... <snipped>


    Thanks for your suggestion.

    Regards,
    Malcolm
    , Apr 29, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kevin Saff

    unget vs. putback

    Kevin Saff, Oct 6, 2003, in forum: C++
    Replies:
    9
    Views:
    517
    James Kanze
    Oct 13, 2003
  2. Jeff Rodriguez

    Reading a file line by line... in reverse

    Jeff Rodriguez, Nov 27, 2003, in forum: C Programming
    Replies:
    4
    Views:
    407
    goose
    Nov 27, 2003
  3. reading line by line from file

    , Mar 29, 2006, in forum: C Programming
    Replies:
    20
    Views:
    692
    CBFalconer
    Mar 31, 2006
  4. Lee Sander
    Replies:
    6
    Views:
    296
    Hendrik van Rooyen
    Jun 1, 2007
  5. scad
    Replies:
    23
    Views:
    1,161
    Alf P. Steinbach
    May 17, 2009
Loading...

Share This Page