and optimally often requires careful thoughtbut once combinedremarkable power is obtained for dealing with largeor even infiniteiterators that could not be done with concrete collections the documentation for the itertools module contain details on its combinatorial functions as well as number of short recipes for combining them this paper does not have space to repeat those descriptionsso just exhibiting few of them above will suffice note that for practical purposeszip()map()filter()and range((which isin sensejust terminating itertools count()could well live in itertools if they were not built-ins that isall of those functions lazily generate sequential items (mostly based on existing iterableswithout creating concrete sequence built-ins like all()any()sum()min()max()and functools reduce(also act on iterablesbut all of themin the general caseneed to exhaust the iterator rather than remain lazy the function itertools prod uct(might be out of place in its module since it also creates concrete cached sequencesand cannot operate on infinite iterators chaining iterables the itertools chain(and itertools chain from_iterable(functions combine multiple iterables built-in zip(and iter tools zip_longest(also do thisof coursebut in manners that allow incremental advancement through the iterables consequence of this is that while chaining infinite iterables is valid syntactically and semanticallyno actual program will exhaust the earlier iterable for examplefrom itertools import chaincount thrice_to_inf chain(count()count()count()conceptuallythrice_to_inf will count to infinity three timesbut in practice once would always be enough howeverfor merely large iterables--not for infinite ones--chaining can be very useful and parsimoniousdef from_logs(fnames)yield from (open(filefor file in fnameslines chain from_iterable(from_logs['huge log''gigantic log']) lazy evaluation