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]
Text editor powered by tinymce.