Calling multiple iterators on xrange objects
generator, iterator, python
Solution
Theres a difference between an iterable and an iterator. You can use `iter(x)` to build an iterator for any given iterable `x`. An iterator encapsulates the state of an iteration, while an iterable is something you can create a new iterator from.
`xrange()` is an iterable, but not an iterator. You can create multiple iterators for a single `xrange()` object, and each of it has its own position.
The `zip()` function implicitly calls `iter()` on each of its arguments. For `zip(*[xrange(5)]*2)`, this will create two iterators for the same `xrange()` objects, each with its own iteration state. For `zip(*[iter(xrange(5))]*2)`, you are already passing in the same iterator twice. Calling `iter()` on an iterator simply returns the iterator itself, so that you end up with only a single iterator in this case.
Problem
Why does ``` zip(*[xrange(5)]*2) ``` give `[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]` but ``` zip(*[iter(xrange(5))]*2) ``` give `[(0, 1), (2, 3)]`? I always though that generator were iterators, so `iter` on a generator was a no-op. For example, ``` list(iter(xrange(5))) [0, 1, 2, 3, 4] ``` is the same as ``` list(xrange(5)) [0, 1, 2, 3, 4] ``` (The same is true for Python 3, but with `list(zip(` and `range`.)