Last but not least, itertools is essential for working with iterable data - like lists. You may not use it often, but it's valuable to know what is available in the module.
I won't cover everything in this step, but here is a link to the documentation for itertools.
But to give an idea for the sorts of things you can do with itertools, check out a few of these examples.
Accumulate allows you to perform some binary function as you iterate through the list. It's very similar to something you might write with map but a bit easier to read. Each element in the resulting iterable is the accumulated value.
By default accumulate adds the values.
list(accumulate([1, 2, 3, 4]))
> [1, 3, 6, 10]
But you can also pass in a binary function as well.
list(accumulate([1, 2, 3, 4], operator.mul))
> [1, 2, 6, 24]
Compress takes data and an iterable, and it return the values from data only when the corresponding value the iterable evalutes to true.
Suppose you have a binary string "Lancelot" and you only want to return values in this string that correspond to 1's in the following list [1, 1, 1, 0, 0, 0, 1, 1].
You could write:
list(compress('Lancelot', [1, 1, 1, 0, 0, 0, 1, 1]))
> ['L', 'a', 'n', 'o', 't']