Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site
Dans les chapitres précédents certaines séries de données ont été abordées : objets 'list', 'range' & 'str'. chaines.
Dans ce chapitre je vais présenter trois autres types de conteneurs : tuple, dictionnaires & ensembles.
Chacun de ces conteneurs a des spécificités qui peuvent être intéressantes en matière de programmation.
En fin de chapitre je vous propose la version presque définitive du programme "tirage au sort de 5 cartes". À cette fin
j'utilise un "set" pour stocker les cartes tirées : les doublons sont alors impossibles simplement par l'emploi de ce type
de série.
Dans un chapitre précédent j'ai évoqué rapidement cette séquence. J'ai montré en effet qu'une fonction pouvait retourner un tuple (plusieurs valeurs séparées par des virgules).
>>> montuple = (5,4,3,2,1) >>> type(montuple) class 'tuple' >>> uneserie =tuple(range(1,6)) >>> uneserie (1, 2, 3, 4, 5) >>> type(uneserie) class 'tuple'
Les valeurs d'un tuple sont encadrées par des parenthèses (ou par aucun symbole).
Pour créer un tuple à partir d'un objet 'range' il faut utiliser la fonction tuple().
>>> del uneserie[0] ... TypeError: 'tuple' object doesn't support item deletion >>> uneserie.append(6) ... AttributeError: 'tuple' object has no attribute 'append' >>> uneserie[0] = 8 ... TypeError: 'tuple' object does not support item assignment >>> uneserie (1, 2, 3, 4, 5)
Comme je le montre ci-dessus, un tuple ne peut être modifié (suppression, ajout, remplacement) après avoir été créé. C'est une structure immuable (comme une chaine).
On peut se demander à quoi ça peut bien servir ce type de données ?
En fait un tuple ça peut être très utile dans certains cas précis que je détaillé ci-dessous.
>>> v1,v2 ="jacques", "louise" >>> v1 'jacques' >>> v2 'louise'
À droite du signe "=" c'est un tuple (j'aurais pu encadrer de parenthèses). Donc en une seule instruction je crée et initialise plusieurs variables simples. Il faut bien sûr que le nombre de variables à gauche du signe d'affectation soit identique au nombre de valeurs du tuple.
La fonction native divmod() retourne le quotient et le reste de la division euclidienne sous forme d'un tuple.
Division entière de 7 par 3 :
>>> euclide = divmod(7,3) >>> euclide (2, 1) >>> euclide[0] 2 >>> euclide[1] 1
La fonction native divmod(dividende, diviseur) retourne un tuple de deux valeurs : quotient puis reste.
Pour éviter de devoir recourir à des extractions, on peut procéder à des affectations multiples comme ci-dessous
lors de l'appel de la fonction.
>>> q,r = divmod(13,2) >>> q 6 >>> r 1
La variable "q" récupère le quotient et "r" récupère le diviseur.
Imaginez une fonction qui doive retourner le périmètre et l'aire d'un rectangle à partir de la longueur et de la largeur.
Dans la fonction les paramètres sont lo (comme longueur), la (comme largeur).
>>> def rectangle(lo,la): ... p =(lo*2) + (la*2) ... a = lo*la ... return p, a # p comme périmètre et a comme aire ... >>> # appel fonction >>> perimetre,aire = rectangle(20,10) >>> perimetre 60 >>> aire 200
Dans la fonction "rectangle" le mot "return" est suivi d'un tuple à deux éléments : p,a.
Notez l'appel de la fonction avec à gauche du signe "=" un tuple à deux éléments.
Ici les tuples ne sont pas encadrés par des parenthèses.
Pour en savoir davantage sur les fonctions visitez les chapitres 5 et 10.
Dans un programme il peut y avoir des variables qui ne doivent pas être modifiées après avoir été initialisées. C'est ce qu'on appelle des constantes. Il suffit donc d'initialiser ces variables particulières à partir d'un tuple.
Exemple :
>>> taux_tva = 20, 5.5 >>> taux_tva[0] 20 >>> taux_tva[1] 5.5 >>> prix_ht = 1000 >>> prix_ht * taux_tva[0] /100 200.0 >>> taux_tva[0] = 18.6 TypeError: 'tuple' object does not support item assignment
La variable "taux_tva" contient un tuple avec deux éléments ; Chaque élément a un indice.
Les taux de TVA sont exprimés pour 100 €, donc je dois diviser par 100 pour obtenir la TVA.
Notez que je n'arrive pas à modifier le contenu du premier élément du tuple ; c'est logique puisqu'un tuple
est une série immuable.
Un tuple est une structure itérable ; peut être parcourue avec un FOR.
>>> montuple = 5,4,3,2,1 >>> for ele in montuple: ... print(ele) ... 5 4 3 2 1 >>> for indice,ele in enumerate(montuple) : ... print(indice,ele) ... 0 5 1 4 2 3 3 2 4 1 >>> ...
On peut parcourir un tuple comme une liste ou une chaine ; c'est une structure itérable.
>>> montuple = (5,4,3,2,1) >>> montuple[0] 5 >>> montuple[1:] (4, 3, 2, 1) >>> montuple.index(1) 4
On peut "slicer" (trancher) un tuple pour extraire une donnée (ou une tranche d'éléments).
La classe 'tuple' dispose de la méthode .index() comme les classes "list" et "str".
>>> var =12,5 >>> type(var) class 'tuple' >>> var =12.5 >>> type(var) class 'float' >>> untuple = 2, >>> type(untuple) class 'tuple' >>>
Vous pouvez créer involontairement un tuple en utilisant par erreur la virgule comme séparateur décimal. ma
Pour créer un tuple avec un seul élément il faut faire suivre celui-ci d'une virgule.
Un dictionnaire n'est pas une série d'éléménts simples mais une suite de paires "clé:valeur".
Dans un dictionnaire on accède donc à une valeur non pas via un indice mais via une clé.
Une paire "clé:valeur" s'appelle aussi un item.
Un dictionnaire en Python est l'équivalent d'un tableau associatif dans d'autres langages.
Dans ce chapitres et pour éviter un débordement dans l'affichage, certaines commandes sont affichées sur deux lignes
avec en fin de première ligne le symbole spécial "\" qui signifie "suite à la ligne suivante".
Ce symbole est parfaitement pris en compte par l'interpréteur Python et s'avère surtout utile dans le cadre d'un script.
>>> mon_inventaire ={"manteaux" : 2, "vestes" : 3, "chemises" : 6, \ "pantalons" : 5} >>> type(mon_inventaire) class 'dict' >>> mon_inventaire["pantalons"] 5 >>> mon_inventaire["pulls"] = 10 >>> mon_inventaire {'manteaux': 2, 'vestes': 3, 'chemises': 6, 'pantalons': 5, 'pulls': 10} >>>del(mon_inventaire["vestes"]) .>>> mon_inventaire {'manteaux': 2, 'chemises': 6, 'pantalons': 5, 'pulls': 10} >>> mon_inventaire['chaussures'] ... KeyError: 'chaussures' >>> mon_inventaire.get('chaussures') >>>
Je crée un dictionnaire nommé "mon_inventaire" qui comprend 4 paires de clé-valeur. Un dictionnaire
est délimité par des accolades.
nomDictionnaire ['pantalons'] pour retourner la valeur correspondant à cette clé.
mon_inventaire["pulls"] = 10 : ajout d'un cinquième paire au dictionnaire.
del(mon_inventaire["vestes"]) : suppression d'une paire du dictionnaire.
mon_inventaire['chaussures'] : la clé est inconnue ; donc un message d'erreur.
Préférez la syntaxe mon_inventaire.get('chaussures') car en cas de clé inconnue il n'y a pas de message d'erreur.
Rappel : un dictionnaire est une séquence non pas d'éléments simples mais d'items c'est à dire de paires "clé:valeur" donc le parcours d'un dictionnaire est différent de celui d'une liste, chaine, tuple.
>>> carnet = {"Pierre" : "pierre.dubus@gmail.com", \ "Pauline" : "duboispauline@hotmail.fr","jacques" : "fredo_jacky@free.fr"} >>> for paire in carnet.items() : ... print(paire) ... ('Pierre', 'pierre.dubus@gmail.com') ('Pauline', 'duboispauline@hotmail.fr') ('jacques', 'fredo_jacky@free.fr') >>>
Il faut appliquer la méthode items() pour afficher les paires "clé:valeur".
>>> for cle in carnet.keys(): ... print(cle) ... Pierre Pauline jacques
Il faut appliquer la méthode keys() pour afficher seulement les clés.
>>> for valeur in carnet.values() : ... print(valeur) ... pierre.dubus@gmail.com duboispauline@hotmail.fr fredo_jacky@free.fr >>>
Il faut appliquer la méthode values() pour afficher seulement les valeurs.
>>> carnet = {"Pierre" : "pierre.dubus@gmail.com", \"Pauline" : "duboispauline@hotmail.fr","jacques" : "fredo_jacky@free.fr"} >>> 'Pauline' in carnet True >>> 'Pauline' in carnet.values() False >>> 'Pauline' in carnet.keys() True >>>
L'occurence 'Pauline' existe dans le dictionnaire et plus précisément c'est une clé (et non pas une valeur). On retrouve donc les méthodes .keys() & .values()
Il peut s'avérer très utile de créer un liste de dictionnairs. On obtient alors une structure de données complexe qui fait penser à une table d'une base de données.
>>> liste_membres =[ {'nom' : 'Dumont', 'mail':'dumont@free.fr'}, \ {'nom' : 'Durand', 'mail':'durand@orange.fr'}] >>> type(liste_membres) class 'list' >>> type(liste_membres[0]) class 'dict' >>> liste_membres =[ {'nom' : 'Dumont', 'mail':'dumont@free.fr'}, \ {'nom' : 'Durand', 'mail':'durand@orange.fr'}] >>> for membre in liste_membres : ... print(membre['nom'], membre['mail']) ... Dumont dumont@free.fr Durand durand@orange.fr >>>
J'ai créé une liste contenant deux dictionnaires. Notez bien la syntaxe : des crochets incluant des paires d'accolades.
Veillez à ce que tous les dictionnaires de la liste aient les mêmes clés (ici nom & mail)
Ensuite je parcours la liste de dictionnaires et pour chaque dictionnaire j'afficher les valeurs pour les clés 'nom' & 'mail'.
Notez bien la syntaxe : print(membre['nom'], membre['mail'])
Je peux parcourir la liste de dictionnaires avec for ... in enumerate ... :
>>> for indice, paire in enumerate(liste_membres): ... print(indice, paire) ... 0 {'nom': 'Dumont', 'mail': 'dumont@free.fr'} 1 {'nom': 'Durand', 'mail': 'durand@orange.fr'}
Python n'est pas avare en séries de données. Depuis la version 3 de Python, il existe un nouveau type de série de données : les ensembles (ou "sets" en anglais).
>>> mon_dico = {"cle1": 10, "cle2" : 15, "cle3":20} >>> type(mon_dico) class 'dict' >>> mon_set = {0,1,2,3,4,5} >>> type(mon_set) class 'set' >>> donnees = {} >>> type(donnees) class 'dict' >>> ensemble =set() >>> type(ensemble) class 'set' >>>
Il ne faut pas confondre les ensembles avec les dictionnaires.
Certes dans les deux cas les délimiteurs sont des accolades. Mais dans un ensemble il n'y a que des éléments simples à la différence
d'un dictionnaire (série de "clé-valeur").
Pour créer un ensemble vide il faut utiliser la syntaxe nomSet =set() alors que pour créer un dictionnaire vide la
commande est plus simplement : nomDictionnaire = {}
À la différence d'une liste, un ensemble ne peut pas contenir une même valeur plusieurs fois ; en d'autres termes il ne peut
y avoir de doublons dans un ensemble.
Cette particularité peut s'avérer très utile en programmation comme je le montre en fin de chapitre avec le jeu "tirage
de 5 cartes".
>>> monset ={3,3,5,5} # impérativemnent une paire d'accolades >>> monset >>> type(monset) class 'set' >>>monset {3, 5}
Si vous tentez de saisir des doublons dans un ensemble, l'interpréteur ne signale aucune erreur mais élimine systématiquement les doublons de la séquence.
>>> liste1 = [1,2,3,4,5,3] >>> ensemble1 = set(liste1) >>> ensemble1 {1, 2, 3, 4, 5} >>>
Le deuxième "3" a disparu de l'ensemble.
>>> ensemble2 = set("anguille") >>> ensemble2 {'l', 'a', 'n', 'i', 'u', 'e', 'g'} >>> ensemble3 = set("lotte de mer") >>> ensemble3 {'r', 'l', 'm', 'd', 'e', ' ', 'o', 't'} >>>
La chaine "anguille" comprend deux "l".
Dans la chaine "lotte de mer" il y a aussi des doublons.
Dans les sets "ensemble2" et "ensemble3" les doublons ont disparu.
>>> ensemble4 =set(range(1,10)) >>> ensemble4 {1, 2, 3, 4, 5, 6, 7, 8, 9} >>> 2 in ensemble4 True >>> "a" in ensemble3 False >>> ensemble4.clear() >>> ensemble4 set()
On peut produire un set d'entiers avec la fonction range().
On peut appliquer l'opérateur "in" à un set.
On peut vider un set avec la méthode .clear().
>>> ensemble3 = set("lotte de mer") >>> ensemble3 {'r', 'd', 'o', 'l', 't', ' ', 'e', 'm'} >>> ensemble3.add('i') >>> ensemble3 {'r', 'd', 'o', 'i', 'l', 't', ' ', 'e', 'm'} >>> ensemble3.add('l') >>> ensemble3 {'r', 'l', 'm', 'd', 'i', 'e', ' ', 'o', 't'}
On a pu ajouter la lettre "i' à l'ensemble. Par contre la tentative d'ajout de la lettre "l" a échoué puisque
cette valeur existait déjà ; il n'y a pas "plantage" de la commande.
Attention : pour ajouter un élément à un set, la méthode est .add() (et non pas .append())
>>> ensemble5 = set(range(1,15,2)) >>> ensemble5 {1, 3, 5, 7, 9, 11, 13} >>> for ele in ensemble5 : ... print(ele) ... 1 3 5 7 9 11 13 >>>
Un ensemble est une structure itérable donc on peut la parcourir avec une boucle.
>>> ensemble5[1] TypeError: 'set' object is not subscriptable >>> ensemble5.index(11) AttributeError: 'set' object has no attribute 'index'
Un ensemble est une série non ordonnée d'éléments uniques. Donc on ne peut donc faire un accès indexé ou une recherche d'index dans un "set".
>>> ens1 = set(range(1,10)) >>> ens1 {1, 2, 3, 4, 5, 6, 7, 8, 9} >>> ens2 = set(range(5,16)) >>> ens2 {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} >>> ens3 = ens1.union(ens2) >>> ens3 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
Le nouveau ensemble ("ens3") est bien l'union de "ens1" et "ens2" ; les valeurs communes aux deux ensembles d'origine ne sont présentes qu'une fois.
>>> ens4 = ens1.intersection(ens2) >>> ens4 {5, 6, 7, 8, 9}
Le nouvel ensemble ("ens4") ne comprend que les éléments qui étaient communs aux deux ensembles d'origine : 5,6,7,8,9.
Vous vous souvenez du programme qui consistait à tirer au sort cinq cartes. Je disais même que ce programme "trichait" puisqu'une même carte pouvait être tirée plusieurs fois. En utilisant un ensemble à la place d'une liste, nous n'avons plus ce problème puisque les doublons sont impossibles dans ce type de série.
# nom programme : tirage_carte_plus.py #objet : tirage au sort de 5 cartes. """ Version améliorée : les cartes tirées sont rangées dans un ensemble. Ainsi il ne peut y avoir de doublons. """ from random import * enseignes = ['pique', 'coeur', 'carreau', 'trèfle'] rang = ['As', 'Roi', 'Dame', 'Valet', 10, 9, 8 , 7] reponse ="o" while reponse in "Oo": mon_jeu =set() # main stockée dans un set vide compteur =0 while len(mon_jeu) < 5 : carte_e = choice (enseignes) carte_r = choice (rang) carte_tiree = str(carte_r) + " de " + carte_e mon_jeu.add(carte_tiree) compteur +=1 print("Mon jeu : ") for carte in mon_jeu: print(carte, end =" - ") print() print(f"Boucle exécutee : {compteur} fois ") print("-------------------------") reponse =input("Voulez vous encore jouer ? : " )
Notez les commentaires multi-lignes : encadrés par trois guillemets.
Notez que la fonction générique len() fonctionne pour tous les types de structures (liste, tuple, dictionnaire, ensemble).
Par contre pour ajouter un élément à un ensemble, la méthode est add() (et non pas append()).
J'ai programmé un compteur d'itérations de la boucle "while len ..." Ainsi je vous montre que pour affecter 5 valeurs à l'ensemble "ma_main" il faut parfois 6 voire 7 itérations de la boucle. En effet l'instruction mon_jeu.add(carte_tiree) ne s'exécute pas si elle aboutit à la création d'un doublon dans le set.
Voulez vous encore jouer ? : o Mon jeu : As de carreau - Roi de trèfle - Dame de pique - Roi de coeur - Roi de carreau - Boucle exécutee : 5 fois ---------------------------------------------- Voulez vous encore jouer ? : o Mon jeu : As de trèfle - Valet de carreau - Valet de trèfle - Dame de trèfle - 9 de carreau - Boucle exécutee : 6 fois ...
Si "ma_main" était un objet de type "list" la programmation aurait été beaucoup plus complexe. Il aurait fallu tester la présence ou pas de doublons alors qu'avec le type 'set" ce contrôle est natif !