Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! Découvrez la Bibliothèque Numérique ENI. Cliquez ici
Formations en ligne à Excel, Word, Office, Teams... Formez-vous en toute autonomie. Je les découvre !
  1. Livres et vidéos
  2. Python
  3. Les boucles, listes et entrées
Extrait - Python Apprenez à développer des projets ludiques (2e édition)
Extraits du livre
Python Apprenez à développer des projets ludiques (2e édition)
4 avis
Revenir à la page d'achat du livre

Les boucles, listes et entrées-sorties

Introduction

Dans ce chapitre, nous présentons les éléments suivants :

  • Les boucles et les conditions imbriquées qui permettent de faire apparaître des structures complexes dans la chaîne de traitement.

  • Les listes qui permettent de stocker plusieurs informations et de retirer ou d’ajouter des informations dynamiquement.

  • La gestion des fichiers qui permet de lire et d’écrire des informations sur le disque.

L’imbrication

1. La notion de blocs d’imbrication

Le branchement d’une instruction if et le corps de boucle d’une instruction for représentent une notion similaire que nous regroupons sous le terme générique de sous-bloc de code. Les sous-blocs, qu’ils soient issus d’un branchement ou d’un corps de boucle, ont la capacité de contenir d’autres sous-blocs. Ils s’imbriquent alors naturellement comme le font les poupées russes.

La différence entre les poupées russes et le code d’un programme, c’est qu’elles ne permettent qu’une seule inclusion par niveau : chaque poupée ne peut contenir qu’une seule autre poupée de taille inférieure, qui elle-même contient aussi une unique autre poupée.

images/04RI00.png

Imbrication des poupées russes

Dans le langage Python, un bloc correspond à des lignes de code successives ayant le même niveau d’indentation. Peuvent être présentes parmi ces lignes d’autres lignes de code de niveau d’indentation inférieur. Ces lignes décrivent alors des sous-blocs relativement au bloc courant. Les instructions : print("bonjour") ou a = b + 1 ne génèrent pas l’apparition de sous-bloc dans les lignes de code. Pour créer une imbrication, il faut passer par une boucle for ou par une condition if. Aux derniers niveaux d’inclusion, on trouve des blocs terminaux ne comportant que des instructions simples sans boucle et sans condition.

L’indentation naturelle du langage Python met en évidence le niveau d’inclusion dans lequel se trouve chaque ligne de code. Analysons un exemple...

Les listes

Nous pourrions faire plusieurs pages d’explication sur les listes, mais c’est un objet très intuitif que nous préférons présenter par l’exemple.  

Si l’on veut stocker l’ensemble des noms des élèves d’une classe, les températures du mois passé ou encore les plaques d’immatriculation d’un parc de véhicules de location, il nous faut une structure nous permettant de stocker plusieurs informations.

Il faut aussi que cette structure puisse évoluer dans le temps car un nouvel élève peut arriver, il faut alors ajouter son nom dans la liste. Un autre élève peut déménager, et dans ce cas, il faut retirer son nom de la liste. On a pu faire une erreur de saisie et un nom a pu être mal orthographié, il faut alors pouvoir le modifier sans toucher aux autres noms présents. Les listes sont faites pour offrir toutes ces fonctionnalités que nous allons présenter dans la suite.  

1. Créer une liste

Nous créons une liste vide en écrivant un symbole crochet ouvrant suivi d’un symbole crochet fermant. Pour créer une liste à partir d’un échantillon de valeurs, nous séparons ces différentes valeurs par des virgules et nous les encadrons par une paire de crochets. Voici un exemple :

L = []                   # Liste vide 
M = [ 11, 12, 15]        # Liste avec trois éléments 
print(M)                 #...

La boucle while et les entrées-sorties fichier

1. La boucle while

Nous allons présenter la structure de boucle utilisant le mot-clé while. Comme pour la condition if, la boucle while nécessite une condition indiquant si son sous-bloc doit être ré-exécuté ou non. Tant que la condition est vraie, son sous-bloc est relancé. Prenons un exemple :

Ouverture d'un fichier texte 
while ( la fin du fichier n'est pas atteinte ) : 
    Charger la prochaine ligne dans le fichier et l'afficher 
Fermeture du fichier 

Cette approche permet de parcourir l’intégralité d’un fichier et de traiter les informations qu’il contient. Il n’est pas possible de connaître la quantité de lignes à lire dans un fichier. Ainsi, on ne peut utiliser une boucle for avec indice. Certes, la taille du fichier est connue, mais on ne peut pas en déduire le nombre de lignes. La boucle while s’adapte très bien à ce scénario.

Il est toujours possible de charger l’intégralité d’un fichier dans une chaîne de caractères et ensuite de parcourir cette chaîne avec une boucle for avec indice. Mais cette approche est une astuce qui devient dangereuse dès que la taille du fichier à traiter devient importante.

2. Ne pas remplacer une boucle for par une boucle while

On peut écrire le code suivant :

K = 10 
while K < 13 : 
     print(K) 
     K += 1          
print("Terminé") 

Cette syntaxe est correcte. Par contre, elle est maladroite. Les trois éléments...

Les listes et chaînes de caractères

1. Conversion entre listes et chaînes

La méthode pour sauvegarder des informations dans un fichier utilisant les fonctions write() et readline() ne vous permet pas de sauvegarder des structures plus complexes comme les listes. Nous aimerions pouvoir écrire : f.write([4,5,6]), mais ce n’est pas possible. Déjà, la fonction write() n’accepte pas les nombres. Certes, on peut trouver une solution en convertissant chaque nombre en chaîne de texte avec la fonction str() avant l’écriture et on peut utiliser la fonction int() pour convertir la chaîne correspondante en nombre lors de la lecture.

Cependant, il y a beaucoup à écrire dans un programme et lorsque les données commencent à devenir complexes et nombreuses, on a envie que les choses se passent simplement et rapidement. Ainsi, lorsqu’on a une liste par exemple, on aimerait avoir une fonction qui convertisse son contenu, quel qu’il soit, c’est-à-dire des chaînes comme des chiffres, en une chaîne de caractères. De plus, il faudrait que cette fonction gère automatiquement la quantité d’éléments présents dans la liste ainsi que le cas particulier des listes vides. Et comme bien souvent en Python, cela existe déjà ! Le package json nous fournit des méthodes permettant de compacter des données quelconques dans une chaîne (les pros disent "sérialiser"). Pour utiliser ces fonctions, il faut importer le package json en début de programme. Un package représente un groupe de fonctions accessibles à travers la syntaxe...

Les messages d’erreur 

1. Les erreurs de crochets

Pour accéder à un élément d’une liste, nous utilisons une paire de crochets contenant un indice entier. Cette syntaxe est source de multiples erreurs :

T = [3,4,5] 
T(4)= 5 

Comme vous l’avez peut-être remarqué, les crochets ont été malencontreusement remplacés par une paire de parenthèses. L’erreur associée est peu compréhensible :

T(4) = 5 
SyntaxError: can't assign to function call 

En fait, dès lors que l’interpréteur voit une paire de parenthèses suivant un identificateur, ici T, il comprend que l’on cherche à appeler une fonction nommée T (voir le chapitre Les fonctions). Un appel de fonction (function call) ne peut pas figurer à gauche d’un symbole = d’affectation, car on attend une variable. Le terme "affectation" se traduisant par "assignment" en anglais, on obtient le message d’erreur : "can’t assign to function call".

2. Les erreurs d’indice

Pour accéder à l’élément d’une liste, il faut utiliser une valeur entière. Voyons ce qu’il se passe dans le cas contraire :

L = [4,5,6] 
k = 1.3 
print(L[k]) 

Le message est clair et vous explique le problème :

print(L[k]) 
TypeError: list indices must be integers or slices, not float 

En anglais, le terme "slice" désigne une plage de valeurs. Ce message signifie donc que l’indice d’une liste doit être un nombre entier ou une plage d’indices, comme [0:4].

3. On mélange les listes et les nombres...

Les trucs en plus

Afin de faire des exercices d’entraînement plus variés, nous allons utiliser des opérateurs et des instructions nouvelles. Nous vous les présentons car, de toute façon, ils font partie des classiques de la programmation.

1. Les paramètres optionnels de la fonction print

Lorsque la fonction print() reçoit plusieurs arguments, par exemple print("un","deux"), elle les affiche en les séparant par un espace. Qu’elle reçoive un ou plusieurs arguments, voire aucun, cette fonction positionne ensuite le curseur à la ligne suivante produisant un retour à la ligne.

Il est possible de modifier ces deux comportements en utilisant des paramètres optionnels :

  • Le paramètre sep permet de changer le séparateur inséré entre les arguments de la fonction print(). Par défaut, c’est un espace qui les sépare.

  • Le paramètre end permet de définir la chaîne qui sera affichée une fois l’affichage des arguments terminés. On peut ainsi contourner le passage à la ligne automatique en fournissant une chaîne vide comme argument. Par défaut, le paramètre end correspond au caractère spécial /n codant un retour à la ligne.

Voici un exemple :

print("Hibou","Caillou") 
print("Toto",end="##",sep="AA") 
print("Titi","Tata","Tutu",end="KK",sep="BB") 
print("============") 
 
>> Hibou Caillou 
>> Toto##TitiBBTataBBTutuKK============ 

Le premier print() a deux arguments. Ainsi...

Exercices d’application

1. Boucles for imbriquées I

Indiquez les valeurs affichées par le programme suivant :

for i in range(3) : 
 for j in range(7): 
   print(i+j,end="") 
 print() 

Correction guidée :

Le bloc principal contient une boucle for i, cet indice va parcourir les valeurs 0, 1 et 2. La boucle for i définit un sous-bloc contenant une boucle for j et une instruction print(). Lorsque que nous entrons dans ce sous-bloc, la valeur de l’indice i est fixée. Par exemple, au premier passage elle vaut 0. La boucle for j effectue une série d’affichages pour j allant de 0 à 6. Comme le retour à la ligne de l’instruction print() est désactivé, les chiffres sont affichés les uns derrière les autres. Une fois la boucle for j terminée, nous passons à l’instruction suivante au même niveau, c’est-à-dire à l’instruction print() qui n’affiche rien, mais produit un retour à la ligne. Ainsi, nous obtenons :

>> 0123456 

Après l’instruction print(), il n’y a plus d’instruction. Nous remontons donc à la boucle for i supérieure. L’indice i change alors pour la valeur 1 et le sous-bloc contenant la boucle for j est relancé avec cette nouvelle valeur. La mécanique à l’intérieur de ce bloc reste la même, seule change la valeur affichée, car cette fois i vaut 1. Nous obtenons ainsi l’affichage suivant :

>> 123457 

Une fois le sous-bloc terminé, nous remontons à la boucle for i pour passer à la dernière valeur à...

Exercices d’entraînement

1. Calculer la somme des éléments d’une liste images/etoile.png

La correction de cet exercice est disponible en téléchargement sur le site de l’éditeur. Pour une liste de nombres entiers, donnez la somme de ses éléments. Pour effectuer ce type de calcul, il faut utiliser une variable supplémentaire qui accumule les valeurs dans la liste lors du parcours. Pensez à initialiser cette variable correctement. La liste est de taille quelconque, tenez-en compte dans l’écriture du programme.

2. Répartir les nombres pairs et impairs dans deux listes images/etoile.png

La correction de cet exercice est disponible en téléchargement sur le site de l’éditeur. Étant donné une liste de nombres entiers, répartissez ces éléments dans une liste IMPAIR contenant les nombres impairs et une liste PAIR contenant les nombres pairs. Affichez le résultat. Pour tester si un nombre k est pair, l’expression k%2 vous sera utile.

3. Compter les occurrences de chaque nombre dans une liste images/etoile.png

La correction de cet exercice est disponible en téléchargement sur le site de l’éditeur. Pour une liste de nombres entiers compris entre 0 et 9, comptez le nombre d’occurrences de chaque nombre dans la liste. Ainsi, pour la liste L = [2, 5, 2, 5, 5, 8], nous avons deux occurrences du chiffre 2, trois occurrences du chiffre 5 et une occurrence du chiffre 8. Nous vous proposons deux approches, vous pouvez programmer l’une ou l’autre :

  • Effectuez d’abord une boucle principale sur les nombres recherchés. Ensuite, faites une boucle imbriquée qui compte le nombre d’occurrences...

Projets

1. Résoudre un cryptarithme images/etoile.pngimages/etoile.png

La correction de ce projet est disponible en téléchargement sur le site de l’éditeur. Un cryptarithme est une suite d’opérations arithmétiques entre des mots dans lesquels chaque lettre correspond à un chiffre. Le codage doit respecter les règles suivantes : une même lettre représente toujours le même chiffre, deux lettres différentes représentent deux chiffres différents. Le but du jeu est de trouver une correspondance entre lettres et chiffres donnant un résultat exact. Voici un exemple :

 

N

E

U

F

 

N -} 1    E -} 5

 

1

5

7

2

+

D

E

U

X

 

F -} 2    D -} 6

 

6

5

7

3

 

--

--

--

-

 

X -} 3    U -} 7

 

--

--

--

--

 

O

N

Z

E

 

Z -} 4    O -} 8

 

8

1

4

5

Nous vous proposons d’écrire un programme pour résoudre le cryptarithme : UN + UN + NEUF = ONZE.

Conseils :

  • Créez des variables pour chaque lettre portant par exemple le même nom.

  • Vous avez en tout six lettres : U, N, E, F, O, Z et vous devez tester pour chacune d’elles les dix chiffres possibles. Vous pouvez un peu optimiser pour la lettre U et la lettre O, car elles ne peuvent être égales à zéro parce qu’elles sont en début de nombre. Ainsi, vous devez générer une boucle for pour chaque lettre et ainsi imbriquer six boucles for.

  • Pensez à vérifier que les lettres correspondent toutes à des chiffres différents. Pour cela, il n’y a pas de méthode élégante à ce stade, il faudra...