Ce cours est visible gratuitement en ligne.

Paperback available in this course

Ce cours existe en eBook.

Certificate of achievement available at the end this course

Got it!
Apprenez à programmer en Python

Apprenez à programmer en Python

Last updated on Monday, September 8, 2014
  • 4 semaines
  • Facile

Les dictionnaires

Maintenant que vous commencez à vous familiariser avec la programmation orientée objet, nous allons pouvoir aller un peu plus vite sur les manipulations « classiques » de ce type, pour nous concentrer sur quelques petites spécificités propres aux dictionnaires.

Les dictionnaires sont des objets pouvant en contenir d'autres, à l'instar des listes. Cependant, au lieu d'héberger des informations dans un ordre précis, ils associent chaque objet contenu à une clé (la plupart du temps, une chaîne de caractères). Par exemple, un dictionnaire peut contenir un carnet d'adresses et on accède à chaque contact en précisant son nom.

Création et édition de dictionnaires

Un dictionnaire est un type de données extrêmement puissant et pratique. Il se rapproche des listes sur certains points mais, sur beaucoup d'autres, il en diffère totalement. Python utilise ce type pour représenter diverses fonctionnalités : on peut par exemple retrouver les attributs d'un objet grâce à un dictionnaire particulier.

Mais n'anticipons pas. Dans les deux chapitres précédents, nous avons découvert les listes. Les objets de ce type sont des objets conteneurs, dans lesquels on trouve d'autres objets. Pour accéder à ces objets contenus, il faut connaître leur position dans la liste. Cette position se traduit par des entiers, appelés indices, compris entre 0 (inclus) et la taille de la liste (non incluse). Tout cela, vous devez déjà le savoir.

Le dictionnaire est aussi un objet conteneur. Il n'a quant à lui aucune structure ordonnée, à la différence des listes. De plus, pour accéder aux objets contenus dans le dictionnaire, on n'utilise pas nécessairement des indices mais des clés qui peuvent être de bien des types distincts.

Créer un dictionnaire

Là encore, je vous donne le nom de la classe sur laquelle se construit un dictionnaire : dict. Vous devriez du même coup trouver la première méthode d'instanciation d'un dictionnaire :

>>> mon_dictionnaire = dict()
>>> type(mon_dictionnaire)
<class 'dict'>
>>> mon_dictionnaire
{}
>>> # Du coup, vous devriez trouver la deuxième manière de créer un dictionnaire vide
... mon_dictionnaire = {}
>>> mon_dictionnaire
{}
>>>

Les parenthèses délimitent les tuples, les crochets délimitent les listes et les accolades {} délimitent les dictionnaires.

Voyons comment ajouter des clés et valeurs dans notre dictionnaire vide :

>>> mon_dictionnaire = {}
>>> mon_dictionnaire["pseudo"] = "Prolixe"
>>> mon_dictionnaire["mot de passe"] = "*"
>>> mon_dictionnaire
{'mot de passe': '*', 'pseudo': 'Prolixe'}
>>>

Nous indiquons entre crochets la clé à laquelle nous souhaitons accéder. Si la clé n'existe pas, elle est ajoutée au dictionnaire avec la valeur spécifiée après le signe =. Sinon, l'ancienne valeur à l'emplacement indiqué est remplacée par la nouvelle :

>>> mon_dictionnaire = {}
>>> mon_dictionnaire["pseudo"] = "Prolixe"
>>> mon_dictionnaire["mot de passe"] = "*"
>>> mon_dictionnaire["pseudo"] = "6pri1"
>>> mon_dictionnaire
{'mot de passe': '*', 'pseudo': '6pri1'}
>>>

La valeur 'Prolixe' pointée par la clé 'pseudo' a été remplacée, à la ligne 4, par la valeur '6pri1'. Cela devrait vous rappeler la création de variables : si la variable n'existe pas, elle est créée, sinon elle est remplacée par la nouvelle valeur.

Pour accéder à la valeur d'une clé précise, c'est très simple :

>>> mon_dictionnaire["mot de passe"]
'*'
>>>

Si la clé n'existe pas dans le dictionnaire, une exception de type KeyError sera levée.

Généralisons un peu tout cela : nous avons des dictionnaires, qui peuvent contenir d'autres objets. On place ces objets et on y accède grâce à des clés. Un dictionnaire ne peut naturellement pas contenir deux clés identiques (comme on l'a vu, la seconde valeur écrase la première). En revanche, rien n'empêche d'avoir deux valeurs identiques dans le dictionnaire.

Nous avons utilisé ici, pour nos clés et nos valeurs, des chaînes de caractères. Ce n'est absolument pas obligatoire. Comme avec les listes, vous pouvez utiliser des entiers comme clés :

>>> mon_dictionnaire = {}
>>> mon_dictionnaire[0] = "a"
>>> mon_dictionnaire[1] = "e"
>>> mon_dictionnaire[2] = "i"
>>> mon_dictionnaire[3] = "o"
>>> mon_dictionnaire[4] = "u"
>>> mon_dictionnaire[5] = "y"
>>> mon_dictionnaire
{0: 'a', 1: 'e', 2: 'i', 3: 'o', 4: 'u', 5: 'y'}
>>>

On a l'impression de recréer le fonctionnement d'une liste mais ce n'est pas le cas : rappelez-vous qu'un dictionnaire n'a pas de structure ordonnée. Si vous supprimez par exemple l'indice 2, le dictionnaire, contrairement aux listes, ne va pas décaler toutes les clés d'indice supérieur à l'indice supprimé. Il n'a pas été conçu pour.

On peut utiliser quasiment tous les types comme clés et on peut utiliser absolument tous les types comme valeurs.

Voici un exemple un peu plus atypique de clés : on souhaite représenter un plateau d'échecs. Traditionnellement, on représente une case de l'échiquier par une lettre (de A à H) suivie d'un chiffre (de 1 à 8). La lettre définit la colonne et le chiffre définit la ligne. Si vous n'êtes pas sûrs de comprendre, regardez la figure suivante.

Échiquier

Pourquoi ne pas faire un dictionnaire dont les clés seront des tuples contenant la lettre et le chiffre identifiant la case, auxquelles on associe comme valeurs le nom des pièces ?

echiquier = {}
echiquier['a', 1] = "tour blanche" # En bas à gauche de l'échiquier
echiquier['b', 1] = "cavalier blanc" # À droite de la tour
echiquier['c', 1] = "fou blanc" # À droite du cavalier
echiquier['d', 1] = "reine blanche" # À droite du fou
# ... Première ligne des blancs
echiquier['a', 2] = "pion blanc" # Devant la tour
echiquier['b', 2] = "pion blanc" # Devant le cavalier, à droite du pion
# ... Seconde ligne des blancs

Dans cet exemple, nos tuples sont sous-entendus. On ne les place pas entre parenthèses. Python comprend qu'on veut créer des tuples, ce qui est bien, mais l'important est que vous le compreniez bien aussi. Certains cours encouragent à toujours placer des parenthèses autour des tuples quand on les utilise. Pour ma part, je pense que, si vous gardez à l'esprit qu'il s'agit de tuples, que vous n'avez aucune peine à l'identifier, cela suffit. Si vous faites la confusion, mettez des parenthèses autour des tuples en toutes circonstances.

On peut aussi créer des dictionnaires déjà remplis :

placard = {"chemise":3, "pantalon":6, "tee-shirt":7}

On précise entre accolades la clé, le signe deux points « : » et la valeur correspondante. On sépare les différents couples clé : valeur par une virgule. C'est d'ailleurs comme cela que Python vous affiche un dictionnaire quand vous le lui demandez.

Certains ont peut-être essayé de créer des dictionnaires déjà remplis avant que je ne montre comment faire. Une petite précision, si vous avez tapé une instruction similaire à :

mon_dictionnaire = {'pseudo', 'mot de passe'}

Avec une telle instruction, ce n'est pas un dictionnaire que vous créez, mais un set.

Un set (ensemble) est un objet conteneur (lui aussi), très semblable aux listes sauf qu'il ne peut contenir deux objets identiques. Vous ne pouvez pas trouver deux fois dans un set l'entier 3 par exemple. Je vous laisse vous renseigner sur les sets si vous le désirez.

Supprimer des clés d'un dictionnaire

Comme pour les listes, vous avez deux possibilités mais elles reviennent sensiblement au même :

  • le mot-clé del ;

  • la méthode de dictionnaire pop.

Je ne vais pas m'attarder sur le mot-clé del, il fonctionne de la même façon que pour les listes :

placard = {"chemise":3, "pantalon":6, "tee shirt":7}
del placard["chemise"]

La méthode pop supprime également la clé précisée mais elle renvoie la valeur supprimée :

>>> placard = {"chemise":3, "pantalon":6, "tee shirt":7}
>>> placard.pop("chemise")
3
>>>

En plus de supprimer la clé et la valeur associée, la méthode pop renvoie cette valeur. Cela peut être utile parfois.

Voilà pour le tour d'horizon. Ce fut bref et vous n'avez pas vu toutes les méthodes, bien entendu. Je vous laisse consulter l'aide pour une liste détaillée.

Un peu plus loin

On se sert parfois des dictionnaires pour stocker des fonctions.

Je vais juste vous montrer rapidement le mécanisme sans trop m'y attarder. Là, je compte sur vous pour faire des tests si vous êtes intéressés. C'est encore un petit quelque chose que vous n'utiliserez peut-être pas tous les jours mais qu'il peut être utile de connaître.

Les fonctions sont manipulables comme des variables. Ce sont des objets, un peu particuliers mais des objets tout de même. Donc on peut les prendre pour valeur d'affectation ou les ranger dans des listes ou dictionnaires. C'est pourquoi je présente cette fonctionnalité à présent, auparavant j'aurais manqué d'exemples pratiques.

>>> print_2 = print # L'objet print_2 pointera sur la fonction print
>>> print_2("Affichons un message")
Affichons un message
>>>

On copie la fonction print dans une autre variable print_2. On peut ensuite appeler print_2 et la fonction va afficher le texte saisi, tout comme print l'aurait fait.

En pratique, on affecte rarement des fonctions de cette manière. C'est peu utile. Par contre, on met parfois des fonctions dans des dictionnaires :

>>> def fete():
...     print("C'est la fête.")
... 
>>> def oiseau():
...     print("Fais comme l'oiseau...")
...
>>> fonctions = {}
>>> fonctions["fete"] = fete # on ne met pas les parenthèses
>>> fonctions["oiseau"] = oiseau
>>> fonctions["oiseau"]
<function oiseau at 0x00BA5198>
>>> fonctions["oiseau"]() # on essaye de l'appeler
Fais comme l'oiseau...
>>>

Prenons dans l'ordre si vous le voulez bien :

  • On commence par définir deux fonctions, fete et oiseau (pardonnez l'exemple).

  • On crée un dictionnaire nommé fonctions.

  • On met dans ce dictionnaire les fonctions fete et oiseau. La clé pointant vers la fonction est le nom de la fonction, tout bêtement, mais on aurait pu lui donner un nom plus original.

  • On essaye d'accéder à la fonction oiseau en tapant fonctions[« oiseau »]. Python nous renvoie un truc assez moche, <function oiseau at 0x00BA5198>, mais vous comprenez l'idée : c'est bel et bien notre fonction oiseau. Toutefois, pour l'appeler, il faut des parenthèses, comme pour toute fonction qui se respecte.

  • En tapant fonctions["oiseau"](), on accède à la fonction oiseau et on l'appelle dans la foulée.

On peut stocker les références des fonctions dans n'importe quel objet conteneur, des listes, des dictionnaires… et d'autres classes, quand nous apprendrons à en faire. Je ne vous demande pas de comprendre absolument la manipulation des références des fonctions, essayez simplement de retenir cet exemple. Dans tous les cas, nous aurons l'occasion d'y revenir.

Les méthodes de parcours

Comme vous pouvez le penser, le parcours d'un dictionnaire ne s'effectue pas tout à fait comme celui d'une liste. La différence n'est pas si énorme que cela mais, la plupart du temps, on passe par des méthodes de dictionnaire.

Parcours des clés

Peut-être avez-vous déjà essayé par vous-mêmes de parcourir un dictionnaire comme on l'a fait pour les listes :

>>> fruits = {"pommes":21, "melons":3, "poires":31}
>>> for cle in fruits:
...     print(cle)
... 
melons
poires
pommes
>>>

Comme vous le voyez, si on essaye de parcourir un dictionnaire « simplement », on parcourt en réalité la liste des clés contenues dans le dictionnaire.

Mais… les clés ne s'affichent pas dans l'ordre dans lequel on les a entrées… c'est normal ?

Les dictionnaires n'ont pas de structure ordonnée, gardez-le à l'esprit. Donc en ce sens oui, c'est tout à fait normal.

Une méthode de la classe dict permet d'obtenir ce même résultat. Personnellement, je l'utilise plus fréquemment car on est sûr, en lisant l'instruction, que c'est la liste des clés que l'on parcourt :

>>> fruits = {"pommes":21, "melons":3, "poires":31}
>>> for cle in fruits.keys():
...     print(cle)
... 
melons
poires
pommes
>>>

La méthode keys (« clés » en anglais) renvoie la liste des clés contenues dans le dictionnaire. En vérité, ce n'est pas tout à fait une liste (essayez de taper fruits.keys() dans votre interpréteur) mais c'est une séquence qui se parcourt comme une liste.

Parcours des valeurs

On peut aussi parcourir les valeurs contenues dans un dictionnaire. Pour ce faire, on utilise la méthode values (« valeurs » en anglais).

>>> fruits = {"pommes":21, "melons":3, "poires":31}
>>> for valeur in fruits.values():
...     print(valeur)
... 
3
31
21
>>>

Cette méthode est peu utilisée pour un parcours car il est plus pratique de parcourir la liste des clés, cela suffit pour avoir les valeurs correspondantes. Mais on peut aussi, bien entendu, l'utiliser dans une condition :

>>> if 21 in fruits.values():
...     print("Un des fruits se trouve dans la quantité 21.")
... 
Un des fruits se trouve dans la quantité 21.
>>>

Parcours des clés et valeurs simultanément

Pour avoir en même temps les indices et les objets d'une liste, on utilise la fonction enumerate, j'espère que vous vous en souvenez. Pour faire de même avec les dictionnaires, on utilise la méthode items. Elle renvoie une liste, contenant les couples clé : valeur, sous la forme d'un tuple. Voyons comment l'utiliser :

>>> fruits = {"pommes":21, "melons":3, "poires":31}
>>> for cle, valeur in fruits.items():
...     print("La clé {} contient la valeur {}.".format(cle, valeur))
... 
La clé melons contient la valeur 3.
La clé poires contient la valeur 31.
La clé pommes contient la valeur 21.
>>>

Il est parfois très pratique de parcourir un dictionnaire avec ses clés et les valeurs associées.

Entraînez-vous, il n'y a que cela de vrai. Pourquoi pas reprendre l'exercice du chapitre précédent, avec notre inventaire de fruits ? Sauf que le type de l'inventaire ne serait pas une liste mais un dictionnaire associant les noms des fruits aux quantités ?

Il nous reste une petite fonctionnalité supplémentaire à voir et on en aura fini avec les dictionnaires.

Les dictionnaires et paramètres de fonction

Cela ne vous rappelle pas quelque chose ? J'espère bien que si, on a vu quelque chose de similaire au chapitre précédent.

Si vous vous souvenez, on avait réussi à intercepter tous les paramètres de la fonction… sauf les paramètres nommés.

Récupérer les paramètres nommés dans un dictionnaire

Il existe aussi une façon de capturer les paramètres nommés d'une fonction. Dans ce cas, toutefois, ils sont placés dans un dictionnaire. Si, par exemple, vous appelez la fonction ainsi : fonction(parametre='a'), vous aurez, dans le dictionnaire capturant les paramètres nommés, une clé 'parametre' liée à la valeur 'a'. Voyez plutôt :

>>> def fonction_inconnue(**parametres_nommes):
...     """Fonction permettant de voir comment récupérer les paramètres nommés
...     dans un dictionnaire"""
...     
...     
...     print("J'ai reçu en paramètres nommés : {}.".format(parametres_nommes))
... 
>>> fonction_inconnue() # Aucun paramètre
J'ai reçu en paramètres nommés : {}
>>> fonction_inconnue(p=4, j=8)
J'ai reçu en paramètres nommés : {'p': 4, 'j': 8}
>>>

Pour capturer tous les paramètres nommés non précisés dans un dictionnaire, il faut mettre deux étoiles ** avant le nom du paramètre.

Si vous passez des paramètres non nommés à cette fonction, Python lèvera une exception.

Ainsi, pour avoir une fonction qui accepte n'importe quel type de paramètres, nommés ou non, dans n'importe quel ordre, dans n'importe quelle quantité, il faut la déclarer de cette manière :

def fonction_inconnue(*en_liste, **en_dictionnaire):

Tous les paramètres non nommés se retrouveront dans la variable en_liste et les paramètres nommés dans la variable en_dictionnaire.

Mais à quoi cela peut-il bien servir d'avoir une fonction qui accepte n'importe quel paramètre ?

Pour l'instant à pas grand chose mais cela viendra. Quand on abordera le chapitre sur les décorateurs, vous vous en souviendrez et vous pourrez vous féliciter de connaître cette fonctionnalité.

Transformer un dictionnaire en paramètres nommés d'une fonction

Là encore, on peut faire exactement l'inverse : transformer un dictionnaire en paramètres nommés d'une fonction. Voyons un exemple tout simple :

>>> parametres = {"sep":" >> ", "end":" -\n"}
>>> print("Voici", "un", "exemple", "d'appel", **parametres)
Voici >> un >> exemple >> d'appel -
>>>

Les paramètres nommés sont transmis à la fonction par un dictionnaire. Pour indiquer à Python que le dictionnaire doit être transmis comme des paramètres nommés, on place deux étoiles avant son nom ** dans l'appel de la fonction.

Comme vous pouvez le voir, c'est comme si nous avions écrit :

>>> print("Voici", "un", "exemple", "d'appel", sep=" >> ", end= -\n")
Voici >> un >> exemple >> d'appel -
>>>

Pour l'instant, vous devez trouver que c'est bien se compliquer la vie pour si peu. Nous verrons dans la suite de ce cours qu'il n'en est rien, en fait, même si nous n'utilisons pas cette fonctionnalité tous les jours.

En résumé

  • Un dictionnaire est un objet conteneur associant des clés à des valeurs.

  • Pour créer un dictionnaire, on utilise la syntaxe dictionnaire = {cle1:valeur1, cle2=valeur2, cleN=valeurN}.

  • On peut ajouter ou remplacer un élément dans un dictionnaire : dictionnaire[cle] = valeur.

  • On peut supprimer une clé (et sa valeur correspondante) d'un dictionnaire en utilisant, au choix, le mot-clé del ou la méthode pop.

  • On peut parcourir un dictionnaire grâce aux méthodes keys (parcourt les clés), values (parcourt les valeurs) ou items (parcourt les couples clé-valeur).

  • On peut capturer les paramètres nommés passés à une fonction en utilisant cette syntaxe : def fonction_inconnue(**parametres_nommes): (les paramètres nommés se retrouvent dans le dictionnaire parametres_nommes).

Example of certificate of achievement
Example of certificate of achievement