Le module itertools est un module bien pratique auquel on ne pense pas assez souvent. En tout cas auquel, moi, je ne pense pas assez souvent. Et pourtant, il peut grandement simplifier pas mal de ligne de code, dans un bon nombre de situation. Il faut juste savoir que les fonctions qu’il propose existe.
Ce billet a donc 2 objectifs, vous faire découvrir les itertools (je ne vais pas lister toutes les fonctions juste celles dont je devrais me servir plus souvent et que j’oublie) et me permettre de ne pas oublier que je pourrais les utiliser.
Point important : Un certain nombre des itertools permettent de gérer les iterateur infinis, ce que ne permettent pas les fonctions ‘normales’ comme map par exemple (qui renvoie une sortie complétement calculée, ce qui est par définition impossible avec un iterateur infini).
Précision : les exemples de code sont ceux fournis par la doc officielle des itertools
itertools.chain (*iterables)
permet d’avoir un iterateur qui retourne tout les éléments du premier iterable passé en paramètre, puis du second, puis du troisième, etc etc… Bien pratique pour aérer son code.
def chain(*iterables):
# chain('ABC', 'DEF') --> A B C D E F
for it in iterables:
for element in it:
yield element
Depuis python 2.6, il existe une classmethod de chain, from_iterable(iterable) qui ne prend qu’un argument, un iterable contenant tout les iterables.
@classmethod
def from_iterable(iterables):
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
for it in iterables:
for element in it:
yield element
itertools.compress(data, selectors)
compress n’est disponible qu’en python 2.7. Cette fonction retourne un iterateur contenant que uniquement les valeurs de data auxquelles correspondent un élément évalué à True dans le selectors. Compress s’arrête dès que data ou selectors est vide.
def compress(data, selectors):
# compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
return (d for d, s in izip(data, selectors) if s)
itertools.count(start=0, step=1)
Cette fonction bien que présente depuis longtemps a droit à quelques modifications dans python 2.7. Count gagne en effet l’argument step et la possibilité d’itérer sur des arguments non integer.
def count(start=0, step=1):
# count(10) --> 10 11 12 13 14 ...
# count(2.5, 0.5) -> 3.5 3.0 4.5 ...
n = start
while True:
yield n
n += step
itertools.dropwhile(predicate, iterable)
Construit un iterateur qui ne renvoie aucun élément de l’iterable tant que le prédicat est vrai, ensuite, tout les éléments de l’iterable sont renvoyés
def dropwhile(predicate, iterable):
# dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
itertools.takewhile(predicate, iterable)
Construit un iterateur qui, tant que le prédicat est vrai, renvoie les éléments de l’iterable.
def takewhile(predicate, iterable):
# takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
for x in iterable:
if predicate(x):
yield x
else:
break
itertools.ifilter(predicate, iterable) et itertools.ifilterfalse(predicate, iterable)
Construit un iterateur qui ne renvoie que les éléments pour lesquels le prédicat est respectivement True ou False. Si predicate est à None, l’iterateur renvoie les éléments respectivement True ou False.
def ifilter(predicate, iterable):
# ifilter(lambda x: x%2, range(10)) --> 1 3 5 7 9
if predicate is None:
predicate = bool
for x in iterable:
if predicate(x):
yield x
itertools.imap(function, *iterables)
Renvoie un iterateur qui applique function en utilisant les iterables comme argument. Si function est None, les arguments sont retournés sous la forme d’un tuple. Imap s’arrête lorsqu’elle atteint la fin du plus petit des iterables. Imap est utile lorsque l’on utilise des iterateur infinie qui provoque une erreur avec map.
def imap(function, *iterables):
# imap(pow, (2,3,10), (5,2,3)) --> 32 9 1000
iterables = map(iter, iterables)
while True:
args = [next(it) for it in iterables]
if function is None:
yield tuple(args)
else:
yield function(*args)
les autres i-versions des fonctions classiques.
Comme l’on trouve imap, il existe aussi izip, izip_longest et islice,
Parmi les autres fonctions il y a des fonctions de combinaisons, de calcul, de cycle, de groupby, mais celles là, vous les trouverez sur la doc officielle.