The itertools module includes a set of functions for working with iterable (sequence-like) data sets.

Iteration Helpers: itertools

Iteration is a big part of the flow of Python and aside from the builtin syntax, there are some handy tools in the itertools package to make things easier. They also tend to make things run faster.

14.4.1. CHAIN()

The chain()method accepts an arbitrary number of iterable objects as arguments and returns an iterator that will iterate over each iterable in turn. Once the first is exhausted, it will move onto the next.

Without the chain() function, iterating over two lists would require creating a copy with the contents of both or adding the contents of one to the other.

More

The functions provided are inspired by similar features of the “lazy functional programming language” Haskell and SML. They are intended to be fast and use memory efficiently, but also to be hooked together to express more complicated iteration-based algorithms.

Iterator-based code may be preferred over code which uses lists for several reasons. Since data is not produced from the iterator until it is needed, all of the data is not stored in memory at the same time. Reducing memory usage can reduce swapping and other side-effects of large data sets, increasing performance.

Merging and Splitting Iterators

The chain() function takes several iterators as arguments and returns a single iterator that produces the contents of all of them as though they came from a single sequence.

fromitertoolsimport*foriinchain([1,2,3],['a','b','c']):printi

$ python itertools_chain.py
1
2
3
a
b
c

izip() returns an iterator that combines the elements of several iterators into tuples. It works like the built-in function zip(), except that it returns an iterator instead of a list.

fromitertoolsimport*foriinizip([1,2,3],['a','b','c']):printi

$ python itertools_izip.py
(1, 'a')
(2, 'b')
(3, 'c')

The islice() function returns an iterator which returns selected items from the input iterator, by index. It takes the same arguments as the slice operator for lists: start, stop, and step. The start and step arguments are optional.

fromitertoolsimport*print'Stop at 5:'foriinislice(count(),5):printiprint'Start at 5, Stop at 10:'foriinislice(count(),5,10):printiprint'By tens to 100:'foriinislice(count(),0,100,10):printi

The tee() function returns several independent iterators (defaults to 2) based on a single original input. It has semantics similar to the Unix tee utility, which repeats the values it reads from its input and writes them to a named file and standard output.

Since the new iterators created by tee() share the input, you should not use the original iterator any more. If you do consume values from the original input, the new iterators will not produce those values:

Converting Inputs

The imap() function returns an iterator that calls a function on the values in the input iterators, and returns the results. It works like the built-in map(), except that it stops when any input iterator is exhausted (instead of inserting None values to completely consume all of the inputs).

In the first example, the lambda function multiplies the input values by 2. In a second example, the lambda function multiplies 2 arguments, taken from separate iterators, and returns a tuple with the original arguments and the computed value.

The starmap() function is similar to imap(), but instead of constructing a tuple from multiple iterators it splits up the items in a single iterator as arguments to the mapping function using the *syntax. Where the mapping function to imap() is called f(i1, i2), the mapping function to starmap() is called f(*i).

Producing New Values

The count() function returns an interator that produces consecutive integers, indefinitely. The first number can be passed as an argument, the default is zero. There is no upper bound argument (see the built-in xrange() for more control over the result set). In this example, the iteration stops because the list argument is consumed.

fromitertoolsimport*foriinizip(count(1),['a','b','c']):printi

$ python itertools_count.py
(1, 'a')
(2, 'b')
(3, 'c')

The cycle() function returns an iterator that repeats the contents of the arguments it is given indefinitely. Since it has to remember the entire contents of the input iterator, it may consume quite a bit of memory if the iterator is long. In this example, a counter variable is used to break out of the loop after a few cycles.

Filtering

The dropwhile() function returns an iterator that returns elements of the input iterator after a condition becomes false for the first time. It does not filter every item of the input; after the condition is false the first time, all of the remaining items in the input are returned.

ifilter() returns an iterator that works like the built-in filter() does for lists, including only items for which the test function returns true. It is different from dropwhile() in that every item is tested before it is returned.

This more complicated example illustrates grouping related values based on some attribute. Notice that the input sequence needs to be sorted on the key in order for the groupings to work out as expected.

fromitertoolsimport*classPoint:def__init__(self,x,y):self.x=xself.y=ydef__repr__(self):return'Point(%s, %s)'%(self.x,self.y)def__cmp__(self,other):returncmp((self.x,self.y),(other.x,other.y))# Create a dataset of Point instancesdata=list(imap(Point,cycle(islice(count(),3)),islice(count(),10),))print'Data:',dataprint# Try to group the unsorted data based on X valuesprint'Grouped, unsorted:'fork,gingroupby(data,lambdao:o.x):printk,list(g)print# Sort the datadata.sort()print'Sorted:',dataprint# Group the sorted data based on X valuesprint'Grouped, sorted:'fork,gingroupby(data,lambdao:o.x):printk,list(g)print

Recently, I try to create a trie tree with python. My data has 3M+ different words, which ate 2G+ of my memory. It made me rather disappointed, so I searched online for solutions. And I found the greatest improvement is to using __slots__ property. It saves me 50% of the memory, so I think this a damn pitfall. Watch out, really, if you've not been familiar with it yet.

The proper use of __slots__ is to save space in objects. Instead of having a dynamic dict that allows adding attributes to objects at anytime, there is a static structure which does not allow additions after creation. This saves the overhead of one dict for every object that uses slots. While this is sometimes a useful optimization, it would be completely unnecessary if the Python interpreter was dynamic enough so that it would only require the dict when there actually were additions to the object.

Unfortunately there is a side effect to slots. They change the behavior of the objects that have slots in a way that can be abused by control freaks and static typing weenies. This is bad, because the control freaks should be abusing the metaclasses and the static typing weenies should be abusing decorators, since in Python, there should be only one obvious way of doing something.

Making CPython smart enough to handle saving space without __slots__ is a major undertaking, which is probably why it is not on the list of changes for P3k (yet).

How to set up shared folders in a Windows XP virtualbox guest (say ubuntu host)?

You have to install the Virtualbox Guest Addition (GA) to be able to share with the host if using Windows.

First create a folder to share in with the host. For example, create a folder called X in your Host's Desktop and before or after installing the Guest Addition right click on the guest os in your Virtualbox main window. Go to settings and look for the Shared Folder option.

Select it and choose the X folder you just made. Now boot the guest OS with the Guest Addition already installed (if you haven't installed it yet do so) and on the terminal type net use x: \\vboxsrv\x that is all. It should tell you that you are now sharing.