Cours Python avec exercices écrit par Christophe Darmangeat dans le cadre du M2 PiSE |
|||||||||||||||||||||
Types compositesEn algorithmique, nous avons vu deux types composites : les tableaux, qui rassemblent des données de même type et qui sont indicés, et les structures, qui rassemblent des données qui peuvent être de types différents, et qui sont dépourvues d'indices. Naturellement, rien n'empêche d'avoir le beurre et l'argent du beurre - la diversité des types et les indices - en combinant les deux dans des tableaux de structures. Python nous propose quatre types composites. Ce sont :
Points communsTous ces types ont en commun de rassembler diverses valeurs. Toutefois, chaque type possède ses propres caractéristiques :
Le dictionnaire étant un composite assez particulier, il n'a pas été inclus dans ce tableau. Mais pas de panique, on s'y intéressera plus tard ! Opérations et opérateurs
Je ne reviens pas sur le découpage, que l'on a déjà rencontré. Voici en revanche quelques exemples des trois autres opérations. Si une variable Duck d'un type composite inclut au départ les éléments 'Riri', 'Fifi' et 'Loulou', et qu'une autre variable Bongo contient 'Pim', 'Pam', 'Poum' :
Méthodes communes
Les listesIl s'agit d'un type qui se rapproche du tableau de l'algorithmique. Une liste peut en théorie contenir des éléments de types différents. Toutefois, en pratique, on évite généralement de mettre cette possibilité à profit, et si l'on a besoin de ranger ensemble des éléments de type différents, on préfèrera opter pour d'autres outils. Pour créer une liste, le plus simple est d'affecter une variable par une suite de valeurs placées entre crochets et séparées par des virgules, par exemple : MaListe = [1, 4, 5, 7, 8, 3] Pour modifier une liste existante, il existe mille possibilités, qui s'organisent en trois grands ensembles d'interventions. Insertion d'élémentsCelle-ci peut s'effectuer par la méthode append, qui ajoute un (ou plusieurs) éléments à la fin d'une liste. Par exemple : MaListe.append(50) MaListe vaut désormais [1, 4, 5, 7, 8, 3, 50] On peut également insérer un élément à un indice spécifique via la méthode insert. On parle bien d'une insertion : dans ce cas, le nouvel élément prend l'indicve spécifié, et toute la partie de la liste qui se trouvait à cet indice et au-delà est auytomatiquement décalée d'un cran. Ainsi, après : MaListe.insert(4, 12) MaListe vaut désormais [1, 4, 5, 7, 12, 8, 3, 50] Suppression d'élémentsPour supprimer un élément, il existe deux instructions, selon que l'on préfère désigner l'élément par sa valeur, ou par son indice. Dans le premier cas, on emploie la méthode remove, avec comme argument la valeur de l'élément à supprimer. Dans le second, on utilise l'instruction del (attention, ce n'est pas une méthode et par conséquent, la syntaxe n'est pas la même !), en spécifiant l'indice de l'élément à supprimer. Par exemple, après : MaListe.remove(8) MaListe vaut désormais [1, 4, 7, 3, 50]. Si j'enchaîne en écrivant : del MaListe[2] MaListe vaut désormais [1, 4, 3, 50] Modification d'élémentsD'une manière générale, on peut modifier un ou plusieurs éléments en les spécifiant et en les affectant avec une nouvelle valeur, selon les règles déjà vues précédemment. Si l'on repart de MaListe = [1, 4, 3, 50], alors : MaListe[1 : 3] = [10, 20, 30] transforme MaListe en [1, 10, 20, 30, 50]. En effet, la plage spécifiée à gauche de l'affectation va des éléments 1 (inclus) à 3 (exclu), autrement dit, elle concerne les éléments d'indice 1 et 2, soit 4 et 3. Elle les remplace par les trois valeurs spécifiées dans la liste située à droite de l'affectation, et « décale 0187 ainsi la valeur 50 – voilà pourquoi les listes ne sont pas tout-à-fait des tableaux.Il existe de très nombreuses méthodes permettant de traiter les listes. Il ne s'agit évidemment pas d'en faire le tour. Deux d'entre elles méritent toutefois d'être signalées, car elles constituent des outils extrêmement puissants pour traiter de longues chaînes de caractère. La première, split, permet de transformer une chaîne en liste, en spécifiant un caractère de séparation. chaine = "Ceci est un essai" result contient à présent ['Ceci', 'est', 'un', 'essai'] On peut opérer le processus inverse, et donc transformer une liste en chaîne, avec la méthode join. Soit la liste alpha = ['A', 'B', 'C', 'D', 'E'], en faisant par exemple : result = ":".join(alpha) result contient alors 'A:B:C:D:E' Des boucles sur les listesComme je l'avais évoqué dans un chapitre précédent, Python comprend plusieurs instructions de boucles spécifiques. L'une d'elles, très pratique, permet d'éviter de gérer l'indice de la liste et d'en récupérer directement les éléments. Admettons que notre liste soit serie = ['i', 'n', 's', 't', 'r', 'u', 'c']. On peut alors écrire directement : for item in serie: La variable item vaudra alors, à chaaque tour de boucle, successivement i, n, s, t, etc. Les TuplesLes tuples sont en tout point semblables aux listes, à cette différence près qu'ils sont immuables, c’est-à-dire qu'une fois un élément inséré dans un tuple, celui-ci n'est pas modifiable. La gamme des possibilités est donc beaucoup plus restreinte. Du point de vue de la syntaxe, le tuple se déclare avec des parenthèses (et non avec des crochets) : MonTuple = ("Veaux", "Vaches", "Cochons", "Poulets") Le tuple est évidemment un outil assez particulier. On s'en sert surtout soit pour stocker des constantes, qui ne devront pas changer de valeur au cours du programme, soit pour contourner les limites théoriques des fonctions et renvoyer ainsi plusieurs valeurs d'un seul coup. Les EnsemblesUn ensemble est un groupement non ordonné d’éléments uniques. Le grand intérêt de l'affaire, c'est que le langage empêche automatiquement la présence de doublons : si on tente d'ajouter un élément (ou plusieurs) à un ensemble qui les contient déjà, il ne se passe tout simplement rien. Pour déclarer et remplir un ensemble, on utilise une paire d'accolades : Couleurs = {'Jaune', 'Vert', 'Rouge', 'Bleu', 'Violet'} Au cas où l'on veuille éclarer un ensemble vide (pour le remplir par la suite), on ne peut pas se contenter d'une paire d'accolades. Il faut alors préciser : CouleursVide = set() À partir de là, on peut faire évoluer un ensemble en ajoutant (méthode add) ou en supprimant des éléments (méthode remove pour une suppression ponctuelle, clear pour le vider complètement). Toutefois, il n'est pas possible de modifier des éléments, car ceux-ci ne sont pas indicés, et donc pas accessibles par cette voie. En revanche, les ensembles se prêtent à de nombreuses opérations qui peuvent être très pratiques.
ConversionsIl est possible de convertir n'importe lequel de ces trois types en n'importe lequel des deux autres, selon une syntaxe classique du cast. Par exemple :
mon_ensemble = set(ma_liste) Ex 1 : Saisie de valeurs Ecrivez un programme qui fait saisir une liste de valeurs, en demandant auparavant combien de valeurs devront être saisies. Le programme affiche ensuite combien de valeurs uniques comprend cette série - on réalisera deux versions de l'exercice : une qui utilise un ensemble, l'autre qui fait le calcul via un algorithme. CombinaisonsIl est possible de combiner ces différents types. Ainsi, une liste de listes correspond peu ou prou à un tableau en deux dimensions. Mais on peut également imaginer une liste de tuples, ou toute autre combinaison. Pour prendre le cas d'une liste de tuples, la syntaxe de la création manuelle ressemblerait à quelque chose comme : personnes = [("Alice", 25), ("Bob", 30), ("Charlie", 22)] On maniera ensuite cette liste comme n'importe quelle autre, en prenant cependant soin de considérer la nature particulière de ses éléments. Ainsi, l'ajout d'un nouvel individu sera : personnes.append(("Dany", 72)) On notera la présence d'une double paire de parenthèses : une pour le append, qui est une méthode, et une Ex 2 : Analyse de fréquence de mots Étant donné une liste de mots saisie au clavier (la saisie se termine par celle d'une chaîne vide), trouvez tous ceux qui apparaissent plus d'une fois et classez-les par ordre de fréquence. Le traitement devra être écrit sous forme de fonction, et le résultat devra être constitué d'une liste de tuples. Ainsi, si les mots saisis sont : chat, chien, oiseau, chat, chien, chien, le programme devra produire [("chien", 3), ("chat", 2)]. – il s'agit donc d'une liste de tuples. NB : Pour effectuer le tri, n'hésitez pas à solliciter internet ! DictionnairesUn dernier type composite est donc le dictionnaire. Ce type établit une correspondance entre deux séries de données (on parle aussi de « tableaux associatifs » ou de « tables de hachage »). Mais là où dans où une liste, les valeurs sont repérées par des nombres entiers (les indices), les dictionnaires sont indexés par des clés, qui peuvent être de n'importe quel type immuable, comme des chaînes de caractères, des nombres ou des tuples. Les listes, en revanche, ne peuvent pas servir de clé puisqu'elles peuvent être modifiées. Les dictionnaires assemblent donc des éléments par paires clé : valeur. Un point essentiel est que les clés doivent impérativement être uniques : on imagine le problème si un même nombre, ou une même chaîne, correspondait à deux valeurs différentes (ou davantage) dans le dictionnaire ; c'est un peu comme si dans un tableau, il pouvait y avoir plusieurs éléments d'indice 7... La syntaxe qui permet de créer et remplir un dictionnaire consiste à définir une suite de paires, c'est-à- dire de deux éléments séparés par le signe :. Ces paires sont elles-mêmes séparées par des virgules, et le tout est entouré par des accolades. Cela donne par exemple : Matricule = {'Jack': 4098, 'Robert': 4139, 'Houria': 7894} Ici, la clé est donc une chaîne de caractères (le prénom), et la valeur associée est un numérique (le matricule). On peut naturellement accomplir diverses opérations sur un dictionnaire. La première d'entre elles consiste à récupérer un élément d'après sa clé. Cela s'effectie exactement avec la même syntaxe que celle qu'on emploie avec une liste. Simplement, entre les crochets, au lieu de placer l'indice, on stipule la valeur de la clé. Ainsi, dans notre exemple, Matricule['Robert'] vaut 4139. Pour ajouter une (paire de) valeurs, il suffit d'affecter une valeur en définissant l'emplacement par la clé : Matricule['James'] = 007 NB : si lors de cette opération, la clé ('James') existe déjà dans le dictionnaire, l'instruction ne provoquera aucune erreur : la valeur précédente correspondant à cette clé sera simplement écrasée – ce qui nous indique donc que l'instruction pour modifier un dictionnaire est exactement la même que pour un ajout. Tout cela fait qu'avant d'ajouter une nouvelle paire, on peut avoir besoin de vérifier que la clé n'est pas déjà présente. Cela s'effectue par l'opérateur in (ou not in), que nous avons déjà rencontré : if 'James' not in Matricule ...alors ce sera un ajout et non une modification. Pour supprimer une (paire de) valeurs, on écrira : del Matricule['James'] Il est même possible de vider d'un coup son dictionnaire, par la méthode clear. Lorsque l'on veut parcourir de manière systématique les éléments d'un dictionnaire, on dispose de trois instructions de boucles spécialement conçues à cette fin, selon que l'on veuille récupérer les clés, les valeurs ou les deux à la fois. Pour récupérer l'ensemble des clés : for k in Matricule.keys(): ...où la variable k contiendra successivement toutes les valeurs des clés, donc dans notre exemple, Jack, Robert, Houria. Pour récupérer l'ensemble des valeurs associées aux clés : for v in Matricule.values(): v vaudra donc successivement 4098, 4139, 7894, etc. Enfin, il est même possible de récupérer les deux à la fois, d'un seul coup d'un seul ! for k, v in Matricule.items(): À chaque tour de boucle, on aura la dans k la valeur de la clé, et dans v la valeur correspondante. Ex 3 : Tirage de cartes L'idée est de simuler le tirage de 5 cartes parmi 52, puis de compter les points que rapportent ces cartes. Le programme affichera donc la série des 5 cartes tirées (roi de carreau, sept de pique, etc.) puis un message : « Cette main vaut ... points ». Pour le comptage des points, les cartes qui affichent un nombre (de 2 à 10) valent les points correspondants ; les figures (valet, dame, roi) valent également 10 points. Enfin, l'as vaut un seule point. Le programme devra obligatoirement travailler à partir de deux composites affectés « en dur » par le programmeur. Le premier sera un tuple comprenant les 4 couleurs. Le second sera un dictionnaire associant les 13 types de cartes à leur valeur en points. Ensuite, tout pourra se faire à partir de ces données de base. Le programme commencera donc par générer les 52 cartes en créant un tuple de tuples à partir de toutes les combinaisons possibles. Enfin, le programme affichera la valeur en points de la main de 5 cartes détenue par le joueur. Ex 4 : Scrabble On simule une partie de Scrabble simplifiée, puisqu'il n'y a qu'un seul joueur et qu'on ne pose pas les lettres sur un plateau. Le joueur reçoit à chaque tour 7 jetons représentant chacun une lettre de l'alphabet (il n'y a pas de jokers). À chaque tour, il doit proposer un mot. La machine vérifie alors que le mot correspond bien aux lettres dont il dispose (cf. exercice 07). Si le mot est validé, on annonce au joueur combien il marque de points, sachant qu'à chaque lettre correspond une valeur donnée. Si le joueur ne propose aucun mot ou qu'il n'y a plus de jetons disponibles, la partie s'arrête. Le but de cette variante est de marquer le plus grand nombre de points par coup. À la fin, on anonce donc cette information au joueur. À noter que dans le cas où le joueur forme un mot de 7 lettres et utilise donc tous ses jetons, il marque un « Scrabble » et reçoit un bonus de 50 points. Attention, pour la distribution des jetons, il faudra bien tenir compte à chaque fois de leur nombre : s'il y a 10 fois plus de E que de Z dans le sac, alors on a 10 fois plus de chances de tirer un E qu'un Z. Les valeurs et les fréquences des jetons sont les suivantes :
|