I was learning the itertools through python docs:
https://docs.python.org/3/library/itertools.html
And at the very end there are recipes that use itertools commands to do simple things, one of them, the consume(), I don't understand it at all:
from itertools import *
def consume(iterator, n):
""""Advance the iterator n-steps ahead. If n is none, consume
entirely."""
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
first of all, this function claims argument to be an iterator, but I found that an iterable will do as well. I think there is a difference between iterable and iterator, right? Because islice() needs no iterator, an iterable could be used
Secondly, When I tried it:
aa = iter([1,2,3,4,5])
print(consume(aa, 2))
it give me None, because islice(iterator, n, n) will always be None no matter what, as (n, n) has no range to be sliced.
And of course if n is None, then I will definitely get None
So it seems like no matter what I do here, I get None as the output anyway, what is the purpose of this function at all?
consume is not supposed to return anything useful. Like the docs says, its purpose is to advance the existing iterator. If you look at aa after your example, you will see it has been advanced:
>>> aa = iter([1,2,3,4,5])
... print(consume(aa, 2))
None
>>> next(aa)
3
Because the use of consume is in its side effect, you can use it on an a "re-iterable" object, but doing so will be useless. What happens is that islice will create an iterator over the object, and advance that iterator, but that won't affect subsequent iteration over the iterable, because a new iterator will be created:
# consuming an iterator
aa = iter([1,2,3,4,5])
consume(aa, 2)
print(list(aa))
# [3, 4, 5]
# "consuming" an iterable
aa = [1,2,3,4,5]
consume(aa, 2)
print(list(aa))
# [1, 2, 3, 4, 5]
In the latter case, all you consumed was a temporary iterator that was created inside consume itself but not returned, so it had no observable effect.
(I use the term "re-iterable" to refer to iterable objects which generate a "fresh" iterator over some stable base data each time iter is called. Lists, for instance, are re-iterables. Every re-iterable object is iterable, but you can write an iterable object which is not re-iterable.)
Iterating through a list is kind of pointless unless you do something with its elements, but advancing through an iterator can execute code; for example, you might be iterating through the values returned by a function with side effects. consume() walks through several elements and throws them away. The general idea (if you don't consume everything) is that it works like seek() in a file handle: When you try to get something out of the iterator afterwards, you will be at a different position.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With