circuitpython_barn-images-12223-unsplash.jpg
Photo by Barn Images on Unsplash

Python has a module designed to make iterators (and by association, generators) easier to use and more flexible: itertools. It contains several functions; we'll look at a few of the more useful. As with functools, this isn't part of CircuitPython, but is part of MicroPython. It provides a subset of CPython's itertools module.

Let's look at a few of the more useful functions available.  It you look at https://docs.python.org/3.6/library/itertools.html you will find more detailed documentation. Also, if you look at https://docs.python.org/3.6/library/itertools.html#itertools-recipes you'll find ways to use the basic functions to build more that can be handy.

The descriptions below should serve to give you a taste of what's possible.

islice(iterable, stop)
islice(iterable, start, stop[, step])

With a list, we can take a slice to extract part of the list:

l = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
l[2:5]
#['c', 'd', 'e']

This doesn't work on an iterable, even though it's still a useful operation.

i = (x for x in ['a', 'b', 'c', 'd', 'e', 'f', 'g'])
i[2:5]
#Traceback (most recent call last):
#File "", line 1, in 
#TypeError: 'generator' object is not subscriptable

This is because the iterable doesn't know about the sequence as a whole; it only knows how to compute the next item.

itertools provides the islice function which does much the same thing for iterators.

islice returns an iterator that iterates over part of the original one. As with list slicing, the stop parameter is the index one past the last item desired. If start is omitted, it is taken as 0. If step is omitted, it is taken as 1. If start is supplied, that many items will be skipped first. If step is supplied and greater than 1, items will be skipped between the ones in the iterator returned by islice

islice('ABCDEFG', 2)
#A B
islice('ABCDEFG', 2, 4)
#C D
islice('ABCDEFG', 2, 7)
#C D E F G
islice('ABCDEFG', 0, 6, 2)
#A C E

count([start, [step]])

The count function returns an infinite iterator that yields a sequence of evenly spaced integers (separated by step) that start at start.

list(islice(count(), 0, 10))
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(islice(count(5), 0, 10))
#[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
list(islice(count(5, 2), 0, 10))
#[5, 7, 9, 11, 13, 15, 17, 19, 21, 23]

cycle(iterable)

This returns an iterator that returns items from the supplied iterable, looping indefinitely. This isn't so good if the supplied iterable is long since the first time through, it might have to cache its contents.

c = cycle('abcd')
next(c)
#'a'
next(c)
#'b'
next(c)
#'c'
next(c)
#'d'
next(c)
#'a'
next(c)
#'b'
next(c)
#'c'
next(c)
#'d'
list(islice(c, 12))
#['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']

cycle can be handy if you, for example, need alternating True/False values:

list(islice(cycle([True, False]), 12))
#[True, False, True, False, True, False, True, False, True, False, True, False]

repeat(object[, n])

This creates an iterator that repeatedly returns object, n times or infinitely if n is omitted. At first this might not seem overly useful, but it can be in specific situations. 

This guide was first published on Oct 11, 2018. It was last updated on Mar 08, 2024.

This page (The itertools Module) was last updated on Mar 08, 2024.

Text editor powered by tinymce.