Jeremy Hylton : weblog : 2003-06-18

itertools

Wednesday, June 18, 2003

Raymond Hettinger's new iterools module has a wonderful collection of features. Iterators and generators seem like they will make some big changes in Python style.

I haven't had much excuse to play with itertools, but a post by Guy Steele on the lightweight languages list gave me an excuse to try it. Steele wrote:

Sometimes an circular structure can be used to "advantage". Consider this bit of code:

(mapcar #'+ x '#1=(1 -1 . #1#))

If x is (1 4 7 10), the result will be (2 3 8 9).

Does this puzzle you? You get 1 point. Does this delight you? You get 5 points. Does this nauseate you? You get 10 points.

The Python version is a bit more verbose. Python doesn't have the nifty syntax for creating recursive objects. In this specific case, the itertools cycle() function suffices.

from itertools import imap, cycle
tuple(imap(int.__add__, (1, 4, 7, 10), cycle((1, -1)))

imap() is an improvement over the builtin map. It doesn't run until it has consumed the longest sequence, which wouldn't make sense for the infinite sequence returned by cycle().

We get to use int.__add__. This is one of my favorite tricks from the type-class unification. There's no need for the operator.add if all the objects are of the same type. Just pass the type's __add__ method.

There is a bit of extra typing required to see the output. An iterator doesn't have a useful repr() for interactive use, so you need to pass it to list() or tuple() or a for loop. Of course, I wouldn't want cycle() to have a "useful repr().