guarding for StopIteration (WAS: Help with generators outside of loops.)

Steven Bethard steven.bethard at gmail.com
Wed Dec 8 03:48:43 EST 2004


Steven Bethard wrote:
> Just to clarify here, the only time code raising a StopIteration will 
> cause a for-loop to exit silently is if the StopIteration is raised in 
> an __iter__ method, e.g.:

That was a little imprecise.  What I should have said is "the only time 
code raising a StopIteration will cause a for-loop to exit silently is 
if the StopIteration is raised in the code that is executed under the 
iteration protocol."

So, using the legacy iterator protocol:

 >>> class C:
...     def __getitem__(self, index):
...         if index > 3:
...             raise IndexError
...         if index == 1:
...             raise StopIteration
...         return index
...
 >>> for i in C():
...     print i
...
0

Or using a separate iterator object:

 >>> class C(object):
...     def __iter__(self):
...         return I()
...
 >>> class I(object):
...     def __init__(self):
...         self.count = -1
...     def next(self):
...         self.count += 1
...         if self.count == 1:
...             raise StopIteration
...         return self.count
...
 >>> for i in C():
...     print i
...
0

Or using a generator to create the iterator object:

 >>> class C(object):
...     def __iter__(self):
...         for i in range(3):
...             if i == 1:
...                 raise StopIteration
...             yield i
...
 >>> for i in C():
...     print i
...
0

Basically, each of these raises a StopIteration in the equivalent of the 
.next method.  If a function that raises a StopIteration is put into any 
of the places where my code says 'raise StopIteration', then that 
StopIteration will silently terminate the loop.

I don't believe there should be any other places where raising a 
StopIteration would silently terminate a loop.

Steve



More information about the Python-list mailing list