How to stop iteration with __iter__() ?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • ssecorp

    How to stop iteration with __iter__() ?

    I want a parse a file of the format:
    movieId
    customerid, grade, date
    customerid, grade, date
    customerid, grade, date
    etc.

    so I could do with open file as reviews and then for line in reviews.

    but first I want to take out the movie id so I use an iterator.

    then i want to iterate through all the rows, but how can I do:
    while movie_iter != None:

    because that doesn't work, itraises an exception, StopItreation, which
    according to the documentation it should. But catching an exception
    can't be the standard way to stop iterating right?
  • Jeff

    #2
    Re: How to stop iteration with __iter__() ?

    On Aug 19, 7:39 am, ssecorp <circularf...@g mail.comwrote:
    I want a parse a file of the format:
    movieId
    customerid, grade, date
    customerid, grade, date
    customerid, grade, date
    etc.
    >
    so I could do with open file as reviews and then for line in reviews.
    >
    but first I want to take out the movie id so I use an iterator.
    >
    then i want to iterate through all the rows, but how can I do:
    while movie_iter != None:
    >
    because that doesn't work, itraises an exception, StopItreation, which
    according to the documentation it should. But catching an exception
    can't be the standard way to stop iterating right?
    No. If you are defining the iterator, then the iterator raises
    StopIteration when it is complete. It is not an exception you
    normally catch; you use a for loop to iterate, and the machinery of
    the for loop uses the StopIteration exception to tell it when to
    break. A file-like object is itself a line iterator, so:

    def review_iter(fil e_obj):
    for line in file_obj:
    if matches_some_pa ttern(line):
    yield line

    Then, to use it:

    file_obj = open('/path/to/some/file.txt')
    try:
    for review in review_iter(fil e_obj):
    do_something(re view)
    finally:
    file_obj.close( )

    Comment

    • Jon Clements

      #3
      Re: How to stop iteration with __iter__() ?

      On Aug 19, 12:39 pm, ssecorp <circularf...@g mail.comwrote:
      I want a parse a file of the format:
      movieId
      customerid, grade, date
      customerid, grade, date
      customerid, grade, date
      etc.
      >
      so I could do with open file as reviews and then for line in reviews.
      >
      but first I want to take out the movie id so I use an iterator.
      >
      then i want to iterate through all the rows, but how can I do:
      while movie_iter != None:
      >
      because that doesn't work, itraises an exception, StopItreation, which
      according to the documentation it should. But catching an exception
      can't be the standard way to stop iterating right?
      Given your example, why not just open the file and call .next() on it
      to discard the first row, then iterate using for as usual?

      hth
      Jon

      Comment

      • Leo Jay

        #4
        Re: How to stop iteration with __iter__() ?

        On Tue, Aug 19, 2008 at 7:39 PM, ssecorp <circularfunc@g mail.comwrote:
        I want a parse a file of the format:
        movieId
        customerid, grade, date
        customerid, grade, date
        customerid, grade, date
        etc.
        >
        so I could do with open file as reviews and then for line in reviews.
        >
        but first I want to take out the movie id so I use an iterator.
        >
        then i want to iterate through all the rows, but how can I do:
        while movie_iter != None:
        >
        because that doesn't work, itraises an exception, StopItreation, which
        according to the documentation it should. But catching an exception
        can't be the standard way to stop iterating right?
        >
        you can use for loop:
        for line in movie_iter:
        ...



        --
        Best Regards,
        Leo Jay

        Comment

        • Terry Reedy

          #5
          Re: How to stop iteration with __iter__() ?



          ssecorp wrote:
          I want a parse a file of the format:
          movieId
          customerid, grade, date
          customerid, grade, date
          customerid, grade, date
          etc.
          >
          so I could do with open file as reviews and then for line in reviews.
          >
          but first I want to take out the movie id so I use an iterator.
          >
          then i want to iterate through all the rows, but how can I do:
          while movie_iter != None:
          >
          because that doesn't work, itraises an exception, StopItreation, which
          according to the documentation it should. But catching an exception
          can't be the standard way to stop iterating right?
          Catching StopIteration *is* the usual way to stop iterating with an
          iterator. Using while, one must be explicit:

          it = iter(iterable)
          try:
          while True:
          item = next(iter) # 2.6,3.0
          f(item)
          except StopIteration:
          pass

          but the main reason to write the above is to show the advantage of
          simply writing the equivalent (and implicit)

          for item in iterable:
          f(item)

          ;-)

          In your case, the standard Python idiom, as Jon said, is

          it = iter(iterable)
          next(it) # 2.6, 3.0
          for for item in iterable:
          f(item)

          The alternative is a flag variable and test

          first = True
          for for item in iterable:
          if first:
          first = False
          else:
          f(item)

          This takes two more lines and does an unnecessary test for every line
          after the first. But this approach might be useful if, for instance,
          you needed to skip every other line (put 'first = True' after f(item)).

          Terry Jan Reedy

          Comment

          • John Machin

            #6
            Re: How to stop iteration with __iter__() ?

            On Aug 20, 5:06 am, Terry Reedy <tjre...@udel.e duwrote:
            In your case, the standard Python idiom, as Jon said, is
            >
            it = iter(iterable)
            next(it) # 2.6, 3.0
            for for item in iterable:
            f(item)
            or, perhaps, for completeness/paranoia/whatever:

            it = iter(iterable)
            try:
            headings = it.next() # < 2.5
            except StopIteration:
            # code to handle empty <iterable>
            for item etc etc
            The alternative is a flag variable and test
            >
            first = True
            for for item in iterable:
            if first:
            first = False
            else:
            f(item)
            >
            This takes two more lines and does an unnecessary test for every line
            after the first. But this approach might be useful if, for instance,
            you needed to skip every other line (put 'first = True' after f(item)).
            and change its name from 'first' to something more meaningful ;-)

            Cheers,
            John

            Comment

            • MRAB

              #7
              Re: How to stop iteration with __iter__() ?

              On Aug 20, 12:11 am, John Machin <sjmac...@lexic on.netwrote:
              On Aug 20, 5:06 am, Terry Reedy <tjre...@udel.e duwrote:
              >
              In your case, the standard Python idiom, as Jon said, is
              >
              it = iter(iterable)
              next(it) # 2.6, 3.0
              for for item in iterable:
                 f(item)
              >
              or, perhaps, for completeness/paranoia/whatever:
              >
              it = iter(iterable)
              try:
                 headings = it.next() # < 2.5
              except StopIteration:
                 # code to handle empty <iterable>
              for item etc etc
              >
              I think it needs to be:

              it = iter(iterable)
              try:
              headings = it.next() # < 2.5
              except StopIteration:
              # code to handle empty <iterable>
              else:
              for item etc etc

              because you don't want to iterate over the remainder if it has already
              stopped yielding! :-)
              The alternative is a flag variable and test
              >
              first = True
              for for item in iterable:
                 if first:
                   first = False
                 else:
                   f(item)
              >
              This takes two more lines and does an unnecessary test for every line
              after the first.  But this approach might be useful if, for instance,
              you needed to skip every other line (put 'first = True' after f(item)).
              >
              and change its name from 'first' to something more meaningful ;-)
              >
              Cheers,
              John

              Comment

              • John Machin

                #8
                Re: How to stop iteration with __iter__() ?

                On Aug 20, 7:56 pm, MRAB <goo...@mrabarn ett.plus.comwro te:
                On Aug 20, 12:11 am, John Machin <sjmac...@lexic on.netwrote:
                >
                or, perhaps, for completeness/paranoia/whatever:
                >
                it = iter(iterable)
                try:
                   headings = it.next() # < 2.5
                except StopIteration:
                   # code to handle empty <iterable>
                for item etc etc
                >
                I think it needs to be:
                >
                it = iter(iterable)
                try:
                    headings = it.next() # < 2.5
                except StopIteration:
                    # code to handle empty <iterable>
                else:
                    for item etc etc
                >
                because you don't want to iterate over the remainder if it has already
                stopped yielding! :-)
                If it has stopped yielding, the remainder is nothing/null/empty, isn't
                it?
                In any case "code to handle empty <iterable>" is likely to end with a
                raise or return statement.

                Cheers,
                John

                Comment

                • MRAB

                  #9
                  Re: How to stop iteration with __iter__() ?

                  On Aug 20, 11:27 am, John Machin <sjmac...@lexic on.netwrote:
                  On Aug 20, 7:56 pm, MRAB <goo...@mrabarn ett.plus.comwro te:
                  >
                  >
                  >
                  On Aug 20, 12:11 am, John Machin <sjmac...@lexic on.netwrote:
                  >
                  or, perhaps, for completeness/paranoia/whatever:
                  >
                  it = iter(iterable)
                  try:
                     headings = it.next() # < 2.5
                  except StopIteration:
                     # code to handle empty <iterable>
                  for item etc etc
                  >
                  I think it needs to be:
                  >
                  it = iter(iterable)
                  try:
                      headings = it.next() # < 2.5
                  except StopIteration:
                      # code to handle empty <iterable>
                  else:
                      for item etc etc
                  >
                  because you don't want to iterate over the remainder if it has already
                  stopped yielding! :-)
                  >
                  If it has stopped yielding, the remainder is nothing/null/empty, isn't
                  it?
                  In any case "code to handle empty <iterable>" is likely to end with a
                  raise or return statement.
                  >
                  So it's defined behaviour that an exhausted iterable will always raise
                  StopIteration no matter how many times it's asked for the next value?

                  Comment

                  • Peter Otten

                    #10
                    Re: How to stop iteration with __iter__() ?

                    MRAB wrote:
                    So it's defined behaviour that an exhausted iterable will always raise
                    StopIteration no matter how many times it's asked for the next value?
                    That is not enforced. However, quoting
                    This document proposes an iteration interface that objects can provide to control the behaviour of for loops. Looping is customized by providing a method that produces an iterator object. The iterator provides a get next value operation that produces ...


                    """
                    Iterator implementations (in C or in Python) should guarantee that
                    once the iterator has signalled its exhaustion, subsequent calls
                    to tp_iternext or to the next() method will continue to do so.
                    """

                    Peter

                    Comment

                    • Steven D'Aprano

                      #11
                      Re: How to stop iteration with __iter__() ?

                      On Wed, 20 Aug 2008 06:16:17 -0700, MRAB wrote:
                      So it's defined behaviour that an exhausted iterable will always raise
                      StopIteration no matter how many times it's asked for the next value?
                      Be careful -- an iterable is not the same as an iterator.

                      Iterables are anything that you can iterate over. This includes strings,
                      lists, tuples, dicts and, yes, iterators.

                      But not all iterables are iterators. Only iterators raise StopIteration.
                      The defined behaviour of iterators is that once exhausted, they will
                      always raise StopIteration.

                      Basically, Python will do the right thing in a for loop regardless of
                      whether you pass an iterator or some other type of iterable. You don't
                      have to worry about the mechanics of it, but if you care, it works
                      something like this:

                      When Python executes a for-loop:

                      for item in obj:
                      BLOCK

                      it does something kind of like this:


                      if hasattr(obj, "next"):
                      # Looks like an iterator.
                      while True:
                      try:
                      item = obj.next()
                      except StopIteration:
                      break
                      execute BLOCK
                      elif hasattr(obj, "__getitem_ _"):
                      # Looks like a string, or list, or similar.
                      i = 0
                      while True:
                      try:
                      item = obj[i]
                      except IndexError:
                      break
                      execute BLOCK
                      i += 1
                      else:
                      raise TypeError('obje ct not iterable')



                      --
                      Steven

                      Comment

                      Working...