Testing for empty iterators?

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

    Testing for empty iterators?

    In the old days, if I wanted to return a sequence of items, I'd return a
    list, and loop over it like this:

    for thing in getListOfThings ():
    do something

    With iterators, I'm doing:

    for thing in getThingIterato r ():
    do something.

    Now I need to test to see if the iterator is empty. Actually, it's a
    unit test where I want to assert that it is empty. In the old days, I
    would have done:

    assertEquals (getListOfThing s (), [])

    but I don't see any clean way to do this with an iterator. The best I
    can come up with is something like:

    flag = False
    for thing in getThingIterato r ():
    flag = True
    break
    assertEquals (flag, False)

    Is that really the only way to do it?
  • Roy Smith

    #2
    Re: Testing for empty iterators?

    I wrote:
    [color=blue]
    > flag = False
    > for thing in getThingIterato r ():
    > flag = True
    > break
    > assertEquals (flag, False)
    >
    > Is that really the only way to do it?[/color]

    Oh, never mind, I got it...

    assertEquals (list (getThingIterat or ()), [])

    Comment

    • Paul McGuire

      #3
      Re: Testing for empty iterators?

      "Roy Smith" <roy@panix.co m> wrote in message
      news:roy-03678F.14110203 072004@reader2. panix.com...[color=blue]
      > I wrote:
      >[color=green]
      > > flag = False
      > > for thing in getThingIterato r ():
      > > flag = True
      > > break
      > > assertEquals (flag, False)
      > >
      > > Is that really the only way to do it?[/color]
      >
      > Oh, never mind, I got it...
      >
      > assertEquals (list (getThingIterat or ()), [])[/color]

      In general, I'd say your first approach was better, or something like:

      try:
      getThingIterato r.next()
      assert False, "getThingIterat or pointed to non-empty iterable"
      except StopIteration:
      pass # no need to assert, by getting here, we know that getThingIterato r
      pointed to an empty iterable

      Or if you'd prefer a more typical-looking assert:

      expectedNullIte m = null
      try:
      expectedNullIte m = getThingIterato r.next()
      except StopIteration:
      pass
      assert expectedNullIte m==null, "getThingIterat or was supposed to be empty"


      Suppose your iterator, through some bug in your code, pointed to a list of
      100,000 database records, instead of an empty list as you expected. Making
      a list from this iterator could be very time-consuming, when all you really
      needed to know was that the iterator pointed to at least one element.

      -- Paul


      Comment

      • Roy Smith

        #4
        Re: Testing for empty iterators?

        "Paul McGuire" <ptmcg@austin.s topthespam_rr.c om> wrote:[color=blue]
        > Suppose your iterator, through some bug in your code, pointed to a list of
        > 100,000 database records, instead of an empty list as you expected. Making
        > a list from this iterator could be very time-consuming, when all you really
        > needed to know was that the iterator pointed to at least one element.[/color]

        I see your point, but this is a unit test. Even more so than normally,
        in a unit test I think clarity of code is more important that
        efficiency. And in this case, it's only inefficient if it fails the
        test, which should never happen :-)

        Comment

        • Michele Simionato

          #5
          Re: Testing for empty iterators?

          Roy Smith <roy@panix.co m> wrote in message news:<roy-0D409A.14060003 072004@reader2. panix.com>...[color=blue]
          > In the old days, if I wanted to return a sequence of items, I'd return a
          > list, and loop over it like this:
          >
          > for thing in getListOfThings ():
          > do something
          >
          > With iterators, I'm doing:
          >
          > for thing in getThingIterato r ():
          > do something.
          >
          > Now I need to test to see if the iterator is empty. Actually, it's a
          > unit test where I want to assert that it is empty. In the old days, I
          > would have done:
          >
          > assertEquals (getListOfThing s (), [])
          >
          > but I don't see any clean way to do this with an iterator. The best I
          > can come up with is something like:
          >
          > flag = False
          > for thing in getThingIterato r ():
          > flag = True
          > break
          > assertEquals (flag, False)
          >
          > Is that really the only way to do it?[/color]

          You may want to check this thread:



          Michele Simionato

          Comment

          • Peter Otten

            #6
            Re: Testing for empty iterators?

            Roy Smith wrote:
            [color=blue]
            > Now I need to test to see if the iterator is empty. Actually, it's a
            > unit test where I want to assert that it is empty. In the old days, I
            > would have done:
            >
            > assertEquals (getListOfThing s (), [])
            >
            > but I don't see any clean way to do this with an iterator. The best I[/color]

            [and in a follow-up]
            [color=blue]
            > Oh, never mind, I got it...
            >
            > assertEquals (list (getThingIterat or ()), [])[/color]

            An alternative would be

            self.assertRais es(StopIteratio n, getThingIterato r().next)

            which is a bit stricter as it will choke if getThingIterato r() returns a
            list instead of an iterator.

            Peter

            Comment

            • Paul Rubin

              #7
              Re: Testing for empty iterators?

              Peter Otten <__peter__@web. de> writes:[color=blue]
              > An alternative would be
              >
              > self.assertRais es(StopIteratio n, getThingIterato r().next)[/color]

              Note that all those methods "consume" at least one element of the
              iterator. You need something like ungetc for iterators (untested code):

              class wrapper:
              def __init__(self, iterator):
              self.iterator = iterator
              self.pushback = []
              def __next__(self):
              if self.pushback:
              return self.pushback.p op(0)
              def is_empty(self):
              if self.pushback:
              return False
              try:
              self.pushback.a ppend(self.iter ator.next())
              return False
              except StopIteration:
              return True

              Maybe something like that should go into itertools, if it's not
              already there. Or the is_empty operation could be built into iterators.

              Comment

              • Larry Bates

                #8
                Re: Testing for empty iterators?

                Normally I add a __len__ method to my class
                that contains an iterator if I need to keep
                track of length/empty status. Basically it
                is something like:

                class getListOfThing:
                def __init__(self):
                self.ListOfThin gs=[]
                self.next_index =0
                #
                # Code to build ListOfThings can be inserted here
                # or in some other method.
                #
                return

                def __iter__(self):
                return self

                def next(self):
                #
                # Try to get the next Thing
                #
                try: Thing=self.List OfThings[self.next_index]
                except IndexError:
                self.next_index =0
                raise StopIteration
                #
                # Increment the index pointer for the next call
                #
                self.next_index +=1
                return Thing

                def __len__(self):
                return len(self.ListOf Things)
                #
                # Where ListOfThings is an attribute
                # (list) that is defined in __init__
                # and appended to in some way.
                #

                if __name__=="__ma in__":

                T=getListOfThin gs()
                print "Length of ListOfThings=", len(T)
                for Thing in T:
                # do something with Thing

                But most of the time the fact that the iterator
                doesn't return enything, so the loop is skipped
                automatically is sufficient. I think you can do
                this same thing with a yield, but this method works
                and I continue to use it a lot.

                HTH,
                Larry Bates
                Syscon, Inc.

                "Roy Smith" <roy@panix.co m> wrote in message
                news:roy-0D409A.14060003 072004@reader2. panix.com...[color=blue]
                > In the old days, if I wanted to return a sequence of items, I'd return a
                > list, and loop over it like this:
                >
                > for thing in getListOfThings ():
                > do something
                >
                > With iterators, I'm doing:
                >
                > for thing in getThingIterato r ():
                > do something.
                >
                > Now I need to test to see if the iterator is empty. Actually, it's a
                > unit test where I want to assert that it is empty. In the old days, I
                > would have done:
                >
                > assertEquals (getListOfThing s (), [])
                >
                > but I don't see any clean way to do this with an iterator. The best I
                > can come up with is something like:
                >
                > flag = False
                > for thing in getThingIterato r ():
                > flag = True
                > break
                > assertEquals (flag, False)
                >
                > Is that really the only way to do it?[/color]


                Comment

                Working...