python itertools: Using cycle with islice
Question: Question:

I have the code below. I want to know why does it not matter whether or not I
include the line with the comment in the code below.

    
    
    #!/usr/bin/env python
    
    from itertools import *
    import time
    cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] )
    p = 3
    while p:
        try:
            for k in cc:
                print k.next()
        except StopIteration:
            p = p - 1
            cc = cycle(islice(cc,  p))  # this does not matter
    

Output:

    
    
    1
    4
    5
    2
    6
    3
    

Also checkout `roundrobin` recipe at

<http://docs.python.org/2.7/library/itertools.html>

This code shows that `islice` is impacting `cc`

    
    
    #!/usr/bin/env python
    
    from itertools import *
    import time
    cc = cycle([ iter([1,2,3]), iter([4]) , iter([5,6]) ] )
    p = 3
    while p:
        try:
            for k in cc:
                print k,k.next()
        except StopIteration:
                print "stop iter"
                p = p - 1
                cc = cycle(islice(cc,  p)) 
    

Output

    
    
    <listiterator object at 0x7f32bc50cfd0> 1
    <listiterator object at 0x7f32bc518050> 4
    <listiterator object at 0x7f32bc518090> 5
    <listiterator object at 0x7f32bc50cfd0> 2
    <listiterator object at 0x7f32bc518050> stop iter
    <listiterator object at 0x7f32bc518090> 6
    <listiterator object at 0x7f32bc50cfd0> 3
    <listiterator object at 0x7f32bc518090> stop iter
    <listiterator object at 0x7f32bc50cfd0> stop iter
    


Answer: Short course: the behaviors with and without rebinding `cc` aren't
**generally** the same, but the outputs **happen** to be the same for the
specific input you used.

Long course: let's call your three iterators A, B and C.

Without the `cc` rebinding: A produces 1, B produces 4, C produces 5, A
produces 2, B raises `StopIteration`. `p` drops to 2. Then C produces 6, A
produces 3, and B raises `StopIteration` **again**. `p` drops to 1. C raises
`StopIteration`. `p` drops to 0, and the loop exits.

With the `cc` rebinding: A produces 1, B produces 4, C produces 5, A produces
2, B raises `StopIteration`. `p` drops to 2. All the same so far. The purpose
of the rebinding in the round-robin algorithm is to **remove** exhausted
iterators. It so happens that in this specific example it makes no difference
to the outcome. With the rebinding `islice(cc, 2)` takes "the next two things"
from `cc`, which are, in order, C and A. B is no longer there. Then C and A
are put in a new `cycle`.

Then C produces 6, A produces 3, and C raises `StopIteration`. `p` drops to 1.
The `cc` rebinding gets rid of C (the exhausted iterator), leaving just A in a
new `cycle`. The loop goes around, and A raises `StopIteration`. `p` drops to
0, and we're done.

Of course removing exhausted iterators is crucial to making round-robin work
correctly in general. But, as you've shown, there are specific cases in which
that doesn't matter :-)

## Simple example

A simple case where rebinding `cc` makes a huge difference:

    
    
    cc = cycle([iter([1,2,3,4,5]), iter([])])
    p = 2
    

With rebinding, we get all 5 values. Without rebinding, we only get 1 and 2.

