itertools – des itérateurs pour des boucles plus efficaces

Le module itertools fournit un ensemble de base d’outils rapides et efficaces en mémoire pour créer des itérateurs avec Python.

itertools

La majorité de ces fonctions créent des générateurs, nous allons parcourir quelques-unes afin de démontrer leur utilisation.

Vous pourrez l’utiliser pour créer vos propres itérateurs qui peuvent être utilisés dans une boucle efficace. Ce module est très utile, donc il est fortement recommandé de prendre le temps de voir ce qu’il a comme fonctionnalités.

Nous allons examiner quelques méthodes utiles qui génèrent des itérateurs. Nous avons trois fonctions intégrées, range(), enumerate() et zip(), qui appartiennent à itertools, mais ils sont si utiles qu’elles sont accessibles directement sans que vous ayez besoin de les importer.

Ce module intègre des fonctions qui utilisent efficacement les ressources de calcul. L’utilisation de ce module tend également à améliorer la lisibilité et la maintenabilité du code.

Pour utiliser ce module, nous devons d’abord l’importer. Il est déjà disponible dans la bibliothèque standard, donc il est pré-installé!

import itertools

itertools.chain() pour enchaîner les itérables


La méthode Python itertools.chain() génère un itérateur à partir de plusieurs itérables.

Cela enchaîne tous les itérables ensemble dans une séquence et renvoie un seul itérateur de cette séquence combinée.

import itertools

list1 = ['bonjour', 'les', 'amis']
list2 = [1, 2, 3]
dict1 = {'site': 'pythonforge', 'url': 'https://pythonforge.com/'}

# nous allons combiner les 3 séquences en une seule chaîne itérable
for item in itertools.chain(list1, list2, dict1):
    print(item)

L’exécution du code.

bonjour
les
amis
1
2
3
site
url

Comme vous pouvez le constater, les valeurs du dictionnaire ne sont pas affichées. Pour résoudre ce problème, nous allons utiliser dict.items() pour obtenir un tuple de paires (clé, valeur).

for item in itertools.chain(list1, list2, dict1.items()):
    print(item)

Les itérateurs infinis avec itertools

Le package itertools est livré avec trois itérateurs qui peuvent itérer à l’infini. Cela signifie que lorsque vous les utilisez, si vous ne sortez pas de ces itérateurs vous aurez une boucle infinie.
Ils peuvent être utiles pour générer des nombres ou parcourir des itérables de longueur inconnue.

count([start=0, step=1])

count() prend deux valeurs : start et step. Il renvoie ensuite une séquence de valeurs à partir de start, avec des intervalles égales à la valeur de step.

from itertools import count
for i in count(10,4):
    print(i)
    if i>25: break

L’exécution du code.

10
14
18
22
26

Essayez d’exécuter ces deux codes.

for i in count(2):
    print(i)
for i in count():
    print(i)

Pour arrêter la boucle infinie, tapez ctl+c. Si vous utilisez Pycharm, cliquez sur le carré rouge.

Une autre méthode que l’on peut utiliser pour limiter la sortie de cet itérateur infini est d’utiliser le sous-module d’itertools, à savoir islice.

from itertools import islice, count
for i in islice(count(2), 5):
    print(i)
2
3
4
5
6

En utilisant islice, nous pouvons limiter le nombre d’itération.

cycle(iterable)

cycle() crée un itérateur à partir d’éléments d’un itérable et enregistre une copie de chacun.

Une fois l’itération terminée, il renvoie les éléments de cette copie encore et encore. Cela se répète indéfiniment.

from itertools import cycle
for i in cycle(['a','b','c']):
    print(i)

Bien sûr, nous ne voulons pas créer un cycle éternel, nous allons donc ajouter un simple compteur avec lequel sortir de la boucle.

from itertools import cycle
count = 0
for i in cycle([1,2,3]):
    if count > 8:
        break
    print(i)
    count += 1

Si vous exécutez ce code, la boucle s’arrêtera à la 9ème itération.

Vous pouvez également utiliser next() qu’on a déjà vu avec les générateurs, pour parcourir les itérateurs que vous créez avec itertools.

from itertools import cycle

maliste = [1,2,3,4,5,6,7,8,9,10]
iterateur = cycle(maliste)
print(next(iterateur))
print(next(iterateur))
print(next(iterateur))
1
2
3

Dans le code ci-dessus, nous avons créé une liste, qui sera passée comme argument à la fonction cycle(). Nous stockons notre nouvel itérateur dans une variable, puis nous passons cette variable à la fonction next(). Chaque fois que nous appelons next(), elle renvoie la valeur suivante dans l’itérateur. Puisque cet itérateur est infini, nous pouvons appeler next() pendant toute la journée.

repeat(elem [,n])

repeat() répétera les éléments n fois ou indéfiniment si vous ne précisez pas le deuxième argument.

from itertools import repeat
for i in repeat('répéter trois fois',3):
    print(i)
répéter trois fois
répéter trois fois
répéter trois fois

À présent nous allons utiliser la fonction next() avec la fonction repeat.

from itertools import repeat
iterateur = repeat('répéter trois fois',3)

print(next(iterateur))
print(next(iterateur))
print(next(iterateur))

# ne sera pas exécutée
print(next(iterateur))

Nous appelons la fonction next() sur notre nouvel itérateur quatre fois pour voir si elle fonctionne correctement. Lorsque vous exécutez ce code, vous verrez que StopIteration est levée, puisque nous avons dépassé la valeur qui détermine le nombre d’itération, qui est de 3.

répéter trois fois
répéter trois fois
répéter trois fois
Traceback (most recent call last):
  File "/home/henke/test.py", line 8, in <module>
    print(next(repeter))
StopIteration

Les itérateurs finis avec itertools

Le module itertools de Python nous fournit différentes manières de manipuler une séquence pendant que nous la parcourons.

chain(*iterables)

Cette fonction accepte un nombre variable d’itérables et les parcourt tous, un par un.

# itérer sur trois listes
import itertools

list_1 = ['a', 'b', 'c']
list_2 =['d', 'e', 'f']
list_3 = ['1', '2', '3']

result = itertools.chain(list_1, list_2, list_3)

for element in result:
  print (element)
a
b
c
d
e
f
1
2
3

compress(data, selectors)

Le sous-module compress est utile pour filtrer le premier itérable avec le second. Cela fonctionne en rendant le deuxième itérable une liste de booléens (des 1 et des 0).

from itertools import compress
letters = 'ABCDEFG'
bools = [True, False, True, True, False]
comp = list(compress(letters, bools))
print(comp)
['A', 'C', 'D']

Nous avons une chaîne de caractère de sept lettres et une liste de cinq Booléens. Ensuite, nous les passons à la fonction de compress. Elle passera par chaque itérable et vérifiera le premier avec le second. Si le second contient un True, alors il sera conservé. S’il s’agit d’un False, cet élément sera supprimé. Ainsi, si vous étudiez l’exemple ci-dessus, vous remarquerez que nous avons un True dans la première, la troisième et la quatrième positions qui correspondent à A, C et D.

dropwhile((func, iterable))

Un itérable et une fonction lui sont transmises. En fonction de la condition à l’intérieur de la fonction, dropwhile continue de supprimer les valeurs de l’itérable jusqu’à ce qu’elle rencontre le premier élément dont la valeur est False. Cela peut allonger le temps de démarrage, c’est donc quelque chose dont il faut être conscient.

from itertools import dropwhile

result = list(dropwhile(lambda x: x<6, [1,3,7,4,5]))

for elements in result:
  print (elements)
7
4
5

La fonction lambda retournera True si x est inférieur à 6. Sinon, elle retournera False. La fonction dropwhile itère sur la liste et passe sur chaque élément dans lambda. Si lambda renvoie True, cette valeur est supprimée. Une fois que nous atteignons le nombre 7, lambda retournera False et nous retenons le nombre 7 et toutes les valeurs qui le suivent.

filterfalse(func, iterable)

Comme son nom l’indique, cet itérateur n’affiche que les valeurs qui renvoient False pour la fonction passée.

import itertools

liste = [2, 4, 5, 7, 8]

print("Les valeurs qui retournent False sont : ", end="")
print(list(itertools.filterfalse(lambda x: x % 2 != 0, liste)))
Les valeurs qui retournent False sont : [2, 4, 8]

itertools.tee () pour cloner des séquences

La fonction tee() créera n itérateurs à partir d’un seul itérable. Cela signifie que vous pouvez créer plusieurs itérateurs à partir d’un itérable.

from itertools import tee
data = '12345'
iter1, iter2 = tee(data)
print("iter1 :")
for item in iter1:
  print(item)
print("iter2 :")
for item in iter2:
  print(item)
iter1 :
1
2
3
4
5
iter2 :
1
2
3
4
5

Les générateurs combinatoires

La bibliothèque itertools possède des itérateurs qui peuvent être utilisés pour créer des combinaisons et des permutations de données.

combinations(iterable, r)

Vous permet de créer un itérateur à partir d’un itérable d’une certaine longueur.

from itertools import combinations
comb = list(combinations('abc', 2))
print(comb)
[('a', 'b'), ('a', 'c'), ('b', 'c')]

combinations_with_replacement(iterable, r)

Cette itérateur est similaire à combinations. La seule différence est qu’il créé des combinaisons où les éléments se répètent.

from itertools import combinations_with_replacement
for item in combinations_with_replacement('abc', 2):

  print(item)
('a', 'a')
('a', 'b')
('a', 'c')
('b', 'b')
('b', 'c')
('c', 'c')

product(*iterables, repeat=1)

Une petite fonction qui créée des produits cartésiens à partir d’une série d’itérables.

from itertools import product
arrays = [(-1,1), (-3,3), (-5,5)]
c = list(product(*arrays))
print(c)
[(-1, -3, -5), (-1, -3, 5), (-1, 3, -5), (-1, 3, 5), (1, -3, -5), (1, -3, 5), (1, 3, -5), (1, 3, 5)]

permutations

Renvoie des permutations successives de longueur r des éléments de l’itérable que vous lui donnez. Les permutations sont émises dans l’ordre de tri lexicographique.

from itertools import permutations

for item in permutations('abc', 2):
  print(item)
('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')

La sortie est un peu plus longue que la sortie des combinaisons.

itertools – des itérateurs pour des boucles plus efficaces

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.

Retour en haut