Testing for empty iterators?

R

Roy Smith

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 getThingIterator ():
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 (getListOfThings (), [])

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 getThingIterator ():
flag = True
break
assertEquals (flag, False)

Is that really the only way to do it?
 
R

Roy Smith

I said:
flag = False
for thing in getThingIterator ():
flag = True
break
assertEquals (flag, False)

Is that really the only way to do it?

Oh, never mind, I got it...

assertEquals (list (getThingIterator ()), [])
 
P

Paul McGuire

Roy Smith said:
I said:
flag = False
for thing in getThingIterator ():
flag = True
break
assertEquals (flag, False)

Is that really the only way to do it?

Oh, never mind, I got it...

assertEquals (list (getThingIterator ()), [])

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

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

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

expectedNullItem = null
try:
expectedNullItem = getThingIterator.next()
except StopIteration:
pass
assert expectedNullItem==null, "getThingIterator 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
 
R

Roy Smith

Paul McGuire said:
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.

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 :)
 
M

Michele Simionato

Roy Smith said:
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 getThingIterator ():
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 (getListOfThings (), [])

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 getThingIterator ():
flag = True
break
assertEquals (flag, False)

Is that really the only way to do it?

You may want to check this thread:

http://groups.google.it/[email protected]&rnum=1

Michele Simionato
 
P

Peter Otten

Roy said:
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 (getListOfThings (), [])

but I don't see any clean way to do this with an iterator. The best I

[and in a follow-up]
Oh, never mind, I got it...

assertEquals (list (getThingIterator ()), [])

An alternative would be

self.assertRaises(StopIteration, getThingIterator().next)

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

Peter
 
P

Paul Rubin

Peter Otten said:
An alternative would be

self.assertRaises(StopIteration, getThingIterator().next)

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.pop(0)
def is_empty(self):
if self.pushback:
return False
try:
self.pushback.append(self.iterator.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.
 
L

Larry Bates

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.ListOfThings=[]
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.ListOfThings[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.ListOfThings)
#
# Where ListOfThings is an attribute
# (list) that is defined in __init__
# and appended to in some way.
#

if __name__=="__main__":

T=getListOfThings()
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top