.. _tut-dict: ***************** Les dictionnaires ***************** Une vidéo de présentation des dictionnaires... .. raw:: html Comme on l'a vu, Python dispose d'un grand nombre de séquences. Tous les langages modernes disposent également d'un ou plusieurs tableaux associatifs. En Python il prend le nom de dictionnaire. Il se définit à partir des opérateurs ``{`` et ``}`` ou du constructeur de la classe :class:`dict`. Le dictionnaire est un container **mutable**. Structure ========= Un dictionnaire est constitué d'un ensemble de paires ``clé:valeur``. La clé doit être un élément **immutable**. Un :class:`dict` conserve l'ordre dans lequel les paires ``clé:valeur`` ont été insérées. >>> d = dict() >>> type(d) On ajoute des éléments à un :class:`dict` avec l'opérateur d'indexation ``[ ]``:: >>> d['Italy'] = 'Rome' >>> d['France'] = 'Paris' >>> d['Spain'] = 'Madrid' >>> d {'Italy': 'Rome', 'France': 'Paris', 'Spain': 'Madrid'} Un :class:`dict` possède un ensemble de méthodes:: >>> dir(d) [..., 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] En particulier, la méthode :meth:`~dict.keys` retourne une vue des clés du dictionnaire:: >>> d.keys() dict_keys(['Italy', 'France', 'Spain']) En particulier, la méthode :meth:`~dict.values` retourne une vue des valeurs associées:: >>> d.values() dict_values(['Rome', 'Paris', 'Madrid']) Les vues sont des objets *itérables*:: >>> for key in d.keys(): ... print(key) ... Italy France Spain On peut également créer un :class:`dict` à partir d'une **sequence** de paires ``clé:valeur``. Cette séquence peut être une :class:`list` de :class:`tuple`:: >>> d = dict([('Italy','Rome'), ('Spain','Madrid'), ('France','Paris')]) >>> d {'Spain': 'Madrid', 'Italy': 'Rome', 'France': 'Paris'} ou un :class:`tuple` de :class:`tuple`:: >>> d = dict((('Italy','Rome'), ('Spain','Madrid'), ('France','Paris'))) >>> d {'Spain': 'Madrid', 'Italy': 'Rome', 'France': 'Paris'} .. _dict_acces_aux_elements: Accès aux éléments ================== Si ``d`` est un :class:`dict`, on accède à ses éléments avec la syntaxe ``d[key]``. Si l'élément existe, il est retourné:: >>> d['Italy'] 'Rome' S'il n'existe pas, une erreur se produit:: >>> d['Portugal'] Traceback (most recent call last): File "", line 1, in KeyError: 'Portugal' :meth:`~dict.get` est une méthode plus sûre. Si l'élément existe, il est retourné. S'il n'existe pas, une valeur par défaut est utilisée. Si elle n'est pas précisée, la valeur par défaut est ``None``:: >>> d.get('Portugal') >>> d.get('Portugal', 'key not in dict') 'key not in dict' Modification de la structure d'un dictionnaire ============================================== Le :class:`dict` étant un élément **mutable**, on peut ajouter des éléments avec la syntaxe ``d[key] = value``:: >>> d['Portugal'] = 'Lisbon' >>> d {'Portugal': 'Lisbon', 'Italy': 'Rome', 'France': 'Paris', 'Spain': 'Madrid'} On peut en retirer avec la syntaxe ``del d[key]``:: >>> del d['Spain'] >>> d {'Portugal': 'Lisbon', 'Italy': 'Rome', 'France': 'Paris'} On peut également utiliser la méthode :meth:`~dict.update` qui prend en argument un second dictionnaire. Le dictionnaire sur lequel la méthode est appelée est modifié avec les paires ``clé:valeur`` qu'il contient:: >>> d.update({'Germany':'Berlin', 'United Kingdom':'London'}) >>> d {'Italy': 'Rome', 'France': 'Paris', 'Portugal': 'Lisbon', 'Germany': 'Berlin', 'United Kingdom': 'London'} .. admonition:: A expérimenter... Ajouter quelques paires clé-valeur au dictionnaire ci dessus avec l'opérateur d'indexation ``[ ]``. Puis de façon groupée à partir d'un second dictionnaire. Itérer sur le dictionnaire ainsi créé en utilisant le :ref:`string_format` des chaines de caractères pour produire un affichage structuré de l'association capitale-pays. Appartenance ============ Comme les **sequences** le :class:`dict` utilise l'opérateur :keyword:`in` pour tester l'appartenance d'une clé ou d'une valeur:: >>> 'Italy' in d.keys() True >>> 'Rome' in d.values() True Tester l'appartenance au dictionnaire lui même fonctionne pour les clés:: >>> 'Italy' in d True mais pas pour les valeurs:: >>> 'Rome' in d False Itérer sur un dictionnaire ========================== La méthode :meth:`~dict.keys` retournant un iterable, on peut utiliser l'opérateur :keyword:`in` pour itérer sur les clés:: >>> for k in d.keys(): ... print(k) ... United Kingdom Italy Germany Portugal France On a constaté plus haut que la méthode :meth:`~dict.keys` retourne une vue des clés du dictionnaire. Cette vue est **dynamique**, c'est à dire qu'elle évolue tout au long de la vie du dictionnaire:: >>> keys = d.keys() >>> keys dict_keys(['United Kingdom', 'Italy', 'Germany', 'Portugal', 'France']) >>> del d['Italy'] >>> keys dict_keys(['United Kingdom', 'Germany', 'Portugal', 'France']) .. note:: Un dictionnaire n'est pas conçu pour itérer sur les valeurs. Au delà des clés et des valeurs, on peut récupérer la paire ``clé-valeur`` dans un :class:`tuple` en une seule opération avec la méthode :meth:`~dict.items`:: >>> for k,v in d.items(): ... print(k,v) ... United Kingdom London Germany Berlin Portugal Lisbon France Paris Autres méthodes =============== Pour une connaissance approfondie des dictionnaires, on consultera la liste des `méthodes `_ associées. Les 'dict comprehension' ======================== Comme pour les :class:`list` et les :class:`set`, il existe une syntaxe compacte pour construire un :class:`dict` : les ``dict comprehension``. L'exemple ci dessous donne le code ASCII des caractères de ponctuation:: >>> import string >>> { char:ord(char) for char in string.punctuation} {']': 93, '&': 38, '~': 126, ... , '/': 47} La sortie a été tronquée pour l'affichage .. _switch: Implémentation de ``switch`` ============================ Comme évoqué au chapître :ref:`tut-controle`, Python ne dispose pas en standard de l'instruction ``switch`` mais une implémentation élégante et compacte est possible avec un dictionnaire:: >>> d = {'a':'Choix A', 'b':'Choix B', 'c':'Choix C'} >>> choix = 'b' >>> print(d[choix]) L'intérêt est de grouper les différents cas sur une seule ligne. Comme en Python tout est objet, les valeurs du dictionnaire peuvent être des fonctions. A titre d'exemple, l'utilisation de ``switch`` en Java: .. code-block:: java :linenos: public class SwitchDemo { public static void main(String[] args) { String choix = 'b'; String res; switch (choix) { case 'a': res = "Choix A"; break; case 'b': res = "Choix B"; break; case 'c': res = "Choix C"; break; } System.out.println(res); } } Ce qu'il faut retenir ===================== .. quiz:: quizz-10 :title: Les dictionnaires - :quiz:`{"type":"TF","answer":"F"}` Un dictionnaire se délimite avec ``[`` et ``]`` - :quiz:`{"type":"TF","answer":"F"}` Un dictionnaire se délimite avec ``(`` et ``)`` - :quiz:`{"type":"TF","answer":"T"}` Un dictionnaire se délimite avec ``{`` et ``}`` - :quiz:`{"type":"TF","answer":"T"}` Les clés d'un dictionnaire sont obligatoirement *immutable* - :quiz:`{"type":"TF","answer":"F"}` Les clés d'un dictionnaire sont toutes de même type - :quiz:`{"type":"TF","answer":"T"}` On peut utiliser des chaines de caractères comme clés d'un dictionnaire - :quiz:`{"type":"TF","answer":"T"}` On peut utiliser des entiers comme clés d'un dictionnaire - :quiz:`{"type":"TF","answer":"T"}` On peut utiliser des tuples comme clés d'un dictionnaire - :quiz:`{"type":"TF","answer":"F"}` On peut utiliser des listes comme clés d'un dictionnaire - :quiz:`{"type":"TF","answer":"F"}` On peut utiliser des sets comme clés d'un dictionnaire - :quiz:`{"type":"TF","answer":"F"}` Les valeurs d'un dictionnaire sont toutes de même type - :quiz:`{"type":"TF","answer":"F"}` Les valeurs d'un dictionnaire sont obligatoirement *immutable* - :quiz:`{"type":"TF","answer":"T"}` Un dictionnaire est *mutable* - :quiz:`{"type":"TF","answer":"T"}` Un dictionnaire est une collection ordonnée - :quiz:`{"type":"TF","answer":"F"}` Une fois créée, la taille d'un dictionnaire est figée - :quiz:`{"type":"TF","answer":"T"}` L'opérateur d'indexation permet d'insérer un élément dans un dictionnaire - :quiz:`{"type":"TF","answer":"F"}` L'opérateur d'indexation permet d'insérer un élément au début d'un dictionnaire - :quiz:`{"type":"TF","answer":"T"}` L'opérateur d'indexation permet d'insérer un élément à la fin d'un dictionnaire - :quiz:`{"type":"FB","answer":"del", "size":5}` permet de supprimer un élément d'un dictionnaire - :quiz:`{"type":"TF","answer":"T"}` Le constructeur d'un dictionnaire peut prendre en paramètre une séquence - :quiz:`{"type":"TF","answer":"F"}` Cette séquence est une séquence de clés - :quiz:`{"type":"TF","answer":"F"}` Cette séquence est une séquence de valeurs - :quiz:`{"type":"TF","answer":"T"}` Cette séquence est une séquence de paires ``clé:valeur`` - La méthode :quiz:`{"type":"FB","answer":"update", "size":5}` permet de modifier un dictionnaire avec un autre dictionnaire - :quiz:`{"type":"TF","answer":"T"}` Sur un dictionnaire, l'opérateur d'appartenance ``in`` fonctionne pour les clés - :quiz:`{"type":"TF","answer":"F"}` Sur un dictionnaire, l'opérateur d'appartenance ``in`` fonctionne pour les valeurs - :quiz:`{"type":"TF","answer":"T"}` On peut parcourir un dictionnaire en itérant sur ses clés - :quiz:`{"type":"TF","answer":"F"}` On peut parcourir un dictionnaire en itérant sur ses valeurs - :quiz:`{"type":"TF","answer":"T"}` On peut construire des dictionnaires imbriqués - Un :quiz:`{"type":"FB","answer":"dict comprehension", "size":18}` est une façon concise de construire un dictionnaire