from itertools import islice, chain, repeat def iterblocks(iterable, size, **kwds): '''Break an iterable into blocks of a given size. The optional keyword parameters determine the type of each block and what to do if the last block has smaller size (by default return it as is). @keyword blocktype: A callable f(iterable) for generating each block (tuple by default). @keyword truncate: If true, drop the last block if its length is less than `size`. @keyword pad: If given, the last block is padded with this object so that is length becomes equal to `size`. @returns: An iterator over blocks of the iterable. >>> list(iterblocks(xrange(7), 3)) [(0, 1, 2), (3, 4, 5), (6,)] >>> list(iterblocks(xrange(7), 3, truncate=True)) [(0, 1, 2), (3, 4, 5)] >>> list(iterblocks(xrange(7), 3, pad=None)) [(0, 1, 2), (3, 4, 5), (6, None, None)] >>> list(iterblocks('abcdefg', 3, pad='-', blocktype=''.join)) ['abc', 'def', 'g--'] ''' truncate = kwds.get('truncate',False) blocktype = kwds.get('blocktype',tuple) if truncate and 'pad' in kwds: raise ValueError("'truncate' must be false if 'pad' is given") iterator = iter(iterable) while True: block = blocktype(islice(iterator,size)) if not block: break if len(block) < size: if 'pad' in kwds: block = blocktype(chain(block, repeat(kwds['pad'], size-len(block)))) elif truncate: break yield block