Any time you want an iterator. That is what iter
is for, it returns an iterator for what you pass to it. So, consider the following generator, which takes advantage of the properties of an iterator, namely, it is single pass and exhaustible, and extracting an iterator from an iterator should return the iterator itself, instead of giving you a new one.
In [19]: import itertools
In [20]: def chunk_by_n(iterable, n):
...: islice = itertools.islice
...: iterator = iter(iterable)
...: chunk = list(islice(iterator, n))
...: while chunk:
...: yield chunk
...: chunk = list(islice(iterator, n))
...:
In [21]: iterable = range(100)
In [22]: chunks = chunk_by_n(iterable, 3)
In [23]: next(chunks)
Out[23]: [0, 1, 2]
In [24]: next(chunks)
Out[24]: [3, 4, 5]
In [25]: next(chunks)
Out[25]: [6, 7, 8]
Now, look what happens if we don't make an iterator out of the input:
In [26]: def chunk_by_n(iterable, n):
...: islice = itertools.islice
...: #iterator = iter(iterable)
...: iterator = iterable
...: chunk = list(islice(iterator, n))
...: while chunk:
...: yield chunk
...: chunk = list(islice(iterator, n))
...:
In [27]: chunks = chunk_by_n(iterable, 3)
In [28]: next(chunks)
Out[28]: [0, 1, 2]
In [29]: next(chunks)
Out[29]: [0, 1, 2]
In [30]: next(chunks)
Out[30]: [0, 1, 2]