Sending StopIteration to for loop from outside of the iterator

for-loop, iterator, loops, python, stopiteration

Solution

You can do something like this with coroutines:

def stoppable_iter(iterable):
    it = iter(iterable)
    for v in it:
        x = yield v
        if x:
            yield
            return

And then use it like this:

it = stoppable_iter(range(10))
for i in it:
    for j in range(10):
        print i, j
        if i*j == 20:
            it.send(StopIteration) # or any value that evaluates as True
            break

And a brief example of how it works:

>>> t = stoppable_iter(range(10))
>>> t.next()
0
>>> t.next()
1
>>> t.send(StopIteration)
>>> t.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Problem

There are several ways to break out of a few nested loops They are: 1) to use break-continue ``` for x in xrange(10): for y in xrange(10): print x*y if x*y > 50: break else: continue # only executed if break was not used break ``` 2) to use return ``` def foo(): for x in range(10): for y in range(10): print x*y if x*y > 50: return foo() ``` 3) to use special exception ``` class BreakIt(Exception): pass try: for x in range(10): for y in range(10): print x*y if x*y > 50: raise BreakIt except BreakIt: pass ``` I had some thought that there could be some other way to do it. It is by using StopIteration exception sent directly to the outer loop. I wrote this code ``` it = iter(range(10)) for i in it: for j in range(10): if i*j == 20: raise StopIteration ``` Unfortunately, StopIteration hadn't been caught by any for-loop and that code produced an ugly Traceback. I think it's because StopIteration wasn't sent from inside of iterator it. (that's my guess, I'm not sure about it). Is there any way that I can send StopIteration to the outer loop? Thanks!

Original source