IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Python, de zéro


précédentsommairesuivant

X. Les iterables

X-1. La notion d’« itérable »

Un itérable est un ensemble de valeurs groupées et pouvant subir une « itération », c’est-à-dire être traité par une boucle qui récupèrera les valeurs une à une.

En effet, dans les programmes usuels, l’immense majorité des opérations se résume généralement à prendre un ensemble d’éléments et les traiter un à un (traiter les clients d’une banque, les comptes bancaires d’un client, les lignes d’opérations dans un compte, les salles de classe d’un lycée, les cours dans une salle, les élèves dans un cours, les fichiers d’un dossier, les lignes d’un fichier, les mots d’une ligne, etc.).

Python a donc été conçu spécifiquement pour offrir des fonctions de manipulation et de gestion de tout ce qui est itérable. Il essaye de rendre itérable tout ce qui semble l’être naturellement (les éléments d’une liste, d’un tuple, d’un dictionnaire, les lettres d’une chaîne, les lignes d’un fichier, etc.) afin d’offrir au programmeur une possibilité accrue d’automatiser facilement ses algorithmes.

Un programmeur Python tentera alors, lui aussi assez naturellement, de favoriser au maximum les itérations dans ses codes.

Exemple : détecter si une personne mesure plus de 175cm et pèse plus de 80kg.

Écriture algorithmique classique :

 
Sélectionnez
1.
2.
if taille > 175 and poids > 80:
    print("trouvé")

Le même programme utilisant une itération sur les critères transformés en itérables :

 
Sélectionnez
1.
2.
3.
4.
for (item, limite) in ((taille, 175), (poids, 80)):
    if item <= limite : break
else:
    print("trouvé")

Dans l'écriture classique, le rajout d’une condition (age > 18 par exemple) se traduira par une réécriture de la condition (rajout d’un and, etc.). Dans la seconde version, cela se traduit juste par un tuple de plus dans l’itérable qui peut être aussi écrit de façon plus lisible.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
for (item, limite) in (
    (taille, 175),
    (poids, 80),
    (age, 18),
):
    if item <= limite : break
else:
    print("trouvé")

Ce qui permet aussi de désactiver/réactiver facilement certaines conditions dans des phases de test.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
for (item, limite) in (
    #(taille, 175),              # Cette ligne est désactivée par le dièse
    #(poids, 80),                # Cette ligne est désactivée par le dièse
    (age, 18),
):
    if item <= limite : break
else:
    print("trouvé")

X-2. Les outils Python

Quelques outils natifs Python permettant de générer et manipuler des itérables

La fonction range(*args) produit une liste de nombres entre :

  • 0 et args[0] (exclu) par pas de 1 si la fonction est appelée avec un seul argument
  • args[0] (inclus) et args[1] (exclu) par pas de 1 si la fonction est appelée avec deux arguments
  • args[0] (inclus) et args[1] (exclu) par pas de args[2] si la fonction est appelée avec trois arguments

Elle permet de créer facilement les indices d'un tuple ou d'une liste.

Dans Python 3, il s’agit d’un générateur (sera vu ultérieurement) tandis que dans Python 2 cette fonction renvoie directement la liste des nombres générés.

La fonction xrange(*args) (Python 2 uniquement) est l’ancien nom de ce qui est devenu range() dans Python 3. Elle produit sa liste de nombres à travers un générateur (sera vu ultérieurement).

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
>>> enfants=("Pim", "Pam", "Poum")
>>> for i in range(len(enfants)): print(i+1, enfants[i])
...
1, Pim
2, Pam,
3, Poum
>>> for i in range(len(enfants), 0, -1): print(i, enfants[i-1])
...
3, Poum
2, Pam,
1, Pim

À noter donc que la fonction range() de Python 2 a disparu dans Python 3 et seule reste la fonction passant par un générateur.

La fonction iter(iterable) crée un itérateur manipulable à partir de l'itérable ou renvoie l'exception TypeError si l'itérable n'en est pas un.

L'accès à l'itérateur se fait ensuite par l'intermédiaire de la fonction next(iterateur[, default]) qui retourne à chaque appel l'élément suivant de l'itérable ; ou lève une exception StopIteration quand il n'y en a plus à moins qu’une valeur par défaut ait été demandée. Auquel cas la fonction retournera indéfiniment cette valeur à chaque appel.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>> enfants=iter(("Pim", "Pam", "Poum"))
>>> while True: print(next(enfants))
...
Pim
Pam,
Poum
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
StopIteration
>>>
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>> enfants=iter(("Pim", "Pam", "Poum"))
>>> while True:
...     n=next(enfants, None)
...     if n is None: break
...     print(n)
...
Pim
Pam
Poum
>>>

À noter que dans Python 2, les itérateurs possèdent aussi une méthode next() qui fait le même travail…

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
# Python 2 uniquement
>>> enfants=iter(("Pim", "Pam", "Poum"))
>>> while True: print(enfants.next())
...
Pim
Pam,
Poum
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
StopIteration

… méthode supprimée dans Python 3, car elle faisait doublon.

La fonction iter(callable, sentinelle) crée un itérateur manipulable à partir d'un élément appelable (généralement une fonction) ou renvoie l'exception TypeError si l'élément n'est pas appelable.

L'accès à l'itérateur se fait ensuite au travers d'une simple itération qui prendra fin soit dès que la sentinelle est atteinte si l'élément correspondant est présent, soit au bout de l'itération si celle‑ci est possible.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
>>> for x in iter(lambda: input("?"), "0"): print(x, type(x))
…
? 5
5 <class 'str'>
? 6
6 <class 'str'>
? 7
7 <class 'str'>
0

La fonction enumerate(iterable, start=0) génère une liste de couples (i, x) où i est un nombre énuméré commençant à start et x l’élément correspondant de l'itérable. Permet de gérer en parallèle les éléments d'un tuple ou d'une liste et le compteur de ces éléments.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
>>> enfants=("Pim", "Pam", "Poum")
>>> for (i, x) in enumerate(enfants, 1): print(i, x)
...
1, Pim
2, Pam,
3, Poum

La fonction reversed(iterable) génère une nouvelle séquence contenant l'itérable inversé

 
Sélectionnez
1.
2.
3.
4.
5.
6.
>>> enfants=("Pim", "Pam", "Poum")
>>> for x in reversed(enfants): print(x)
...
Poum
Pam,
Pim

La fonction sorted(iterable, key=None, reverse=False) génère une nouvelle séquence contenant l'itérable trié selon la valeur de la clef.

Si l’argument key est demandé, cet argument devra être une fonction à un paramètre (paramètre présumé être un élément de l’itérable) permettant de considérer selon un algorithme particulier tout élément pour utiliser cette considération comme clef de comparaison. Sinon l’évaluation se fera sur la valeur numérique de l’élément dans son ensemble (les items alphabétiques étant alors convertis en nombres correspondant en Unicode).

Le tri peut être inversé si l'argument reverse est mis à True.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
>>> auteurs=("Hugo", "Racine", "Balzac")
>>> for x in sorted(auteurs, key=lambda x: x[2]): print(x)        # Tri sur le 3° caractère
...
Racine
Hugo
Balzac

À noter : dans Python 2, la fonction sorted() dispose d'un argument supplémentaire cmp=None. Cet argument permet de recevoir une fonction externe programmée pour comparer deux éléments distincts. Cette fonction devant renvoyer un nombre négatif, positif ou nul selon que l’élément 1 est plus petit, plus grand ou égal à l’élément 2. Les éléments à comparer sont alors issus soit du retour de la fonction passée à l'argument key si celui‑ci est présent ; soit de l'itérable lui‑même.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
# Exemple Python 2 uniquement

# La fonction va trier alphabétiquement chaque chaîne inversée ("abc" vu comme "cba")
def compare(x, y):
    if x[::-1] < y[::-1]: return -1
    if x[::-1] > y[::-1]: return 1
    return 0

>>> auteurs=("Hugo", "Racine", "Balzac")
>>> for x in sorted(auteurs, cmp=compare, reverse=True): print x
...
Hugo
Racine
Balzac

L’argument cmp a disparu dans Python 3 parce qu’il était déprécié (dans la majorité des cas on peut s’en sortir avec l’argument key).

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
# Le même exemple Python 3 utilisant l’argument key

>>> auteurs=("Hugo", "Racine", "Balzac")
>>> for x in sorted(auteurs, key=lambda x: x[::-1], reverse=True): print(x)
...
Hugo
Racine
Balzac

Mais si vraiment cela devient nécessaire, son comportement peut être reproduit en utilisant l'objet cmp_to_key() du module functools (sera vu ultérieurement). Cet objet convertira la fonction en clef, objet qu'on passera alors à l'argument key.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
# Le même exemple Python 3 utilisant cmp_to_key

# La fonction va trier alphabétiquement chaque chaîne inversée ("abc" vu comme "cba")
def compare(x, y):
    if x[::-1] < y[::-1]: return -1
    if x[::-1] > y[::-1]: return 1
    return 0

from functools import cmp_to_key

>>> auteurs=("Hugo", "Racine", "Balzac")
>>> for x in sorted(auteurs, key=cmp_to_key(compare), reverse=True): print(x)
...
Hugo
Racine
Balzac

précédentsommairesuivant

Copyright © 2022 Svear (svear@free.fr) Permission est accordée de copier, distribuer ou modifier ce document selon les termes de la « Licence de Documentation Libre GNU » (GNU Free Documentation License), version 1.1 ou toute version ultérieure publiée par la Free Software Foundation.