Python iterators and Haskell lists are different things. We have not yet had to reckon with this fact, but for this lesson we can no longer look past the distinction.
Python iterators are mutable
First we’ll set up an example to illustrate why
itertools.tee exists. Let’s say we start with an iterator that represents all of the natural numbers starting from 1:
And then we define two more iterators based on
it; one that filters to get only the evens, and another that filters to get only the odds.
If we sample the first five evens and the first five odds, we might hope to get
2,4,6,8,10 for the evens and
1,3,5,7,9 for the odds. But this isn’t what happens:
Why not? Because
it isn’t really a representation of all the natural numbers starting from 1. It’s more like a mutable database of numbers, and each time something interacts with
it, it changes. When we first create it, it’s a sequence starting from 1.
But as soon as we apply
next to it, it’s now a sequence starting from two.
And we can observe the change because, the next time we interact with
it, something different happens.
Haskell lists are immutable
Haskell lists don’t work like this. If we define a list starting at one,
then the first element in the list is 1, and it is always 1 no matter how many times we ask.
So when we try the even-and-odd experiment again, we get the expected result.
For Python iterators,
itertools.tee is there to deal with this issue. We can use
tee to fork the original iterator into two copies that each have their own separate internal state.
it_2 are independent; we can use one without affecting the other.
This is the last of our lessons on
itertools functions. Next we’ll move onto other topics!