On Aug 15, 9:55 pm, Fredrik Lundh <[EMAIL PROTECTED]> wrote: > Lie wrote: > > When you've got a nested loop a StopIteration in the Inner Loop would > > break the loop for the outer loop too: > > > a, b, c = [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5] > > > def looper(a, b, c): > > for a_ in a: > > for b_ in b: > > for c_ in c: > > print a_, b_, c_ > > > looper(a, b, c) # Intended behavior [1] > > a, b, c = iter(a), b, iter(c) # b is intentionally not iter()-ed > > looper(a, b, c) # Inner StopIteration prematurely halt outer loop [2] > > iterators are once-only objects. there's nothing left in "c" when you > enter the inner loop the second time, so nothing is printed. >
Ah, now I see. You have to "restart" the iterator if you want to use it the second time (is it possible to do that?). > >>> a = range(10) > >>> a = range(5) > >>> a = iter(a) > >>> for i in a: > ... print i > ... > 0 > 1 > 2 > 3 > 4 > >>> for i in a: > ... print i > ... > >>> > > > This is a potential problem since it is possible that a function that > > takes an iterable and utilizes multi-level looping could be > > prematurely halted and possibly left in intermediate state just by > > passing an iterator. > > it's a problem only if you confuse iterators with sequences. I see, but if/when a function expects a sequence but then fed with an iterator, it would be against duck-typing to check whether something is a sequence or an iterator, but iterator is good for one iteration only while sequence is good for multiple usage. So is there a clean way to handle this? (i.e. a design pattern that allows sequence and iterator to be treated with the same code) If there is no such design pattern for that problem, should one be available? I'm thinking of one: "all iterables would have iterable.restart() method, which is defined as 'restarting the iterator for iterator' or 'do nothing for sequences'." Then both sequence and list can be treated like this: for a_ in a: b.restart() for b_ in b: c.restart() for c_ in c: print a_, b_, c_ This is useful if b, c is huge (so copying the list is out of the question) but needs to be used multiple times in a nested loop. For the general cases where the iterators is used only once, iterable.restart() wouldn't need to be called at all and wouldn't even need a code change (on the spirit of make the common things easy and the rare thing possible). Wait a minute... I've got an idea, we could use itertools.tee to copy the iterator and iterating on the copy, like this right?: for a_ in a: b, b_copy = itertools.tee(b) for b_ in b_copy: c, c_copy = itertools.tee(c) for c_ in c_copy: print a_, b_, c_ That works with both "requirement": able to handle sequence and iterator with the same code and the code for common cases where iterators are used once only wouldn't need to be changed. Personally though, I don't think it's a clean solution, looks a bit of hackery. > </F> -- http://mail.python.org/mailman/listinfo/python-list