12 - Dictionnaires

Vidéo : les dictionnaires en Python (7 min 38)

Pourquoi des dictionnaires ?

Dans une liste, on accède aux éléments par leur indice (un numéro). Mais ce n’est pas toujours la façon la plus naturelle de retrouver une information. Quand on cherche un numéro dans un annuaire, on ne dit pas « je veux l’élément n°37 » mais « je veux le numéro d’Alice ».

Avec une liste, pour afficher le numéro de Bob, il faut savoir que ce numéro se trouve à l’indice 1 :

numeros = ["06 12 34 56 78", "07 98 76 54 32"]
print(numeros[1])
07 98 76 54 32

Avec un dictionnaire, à chaque prénom correspond un numéro, et le prénom suffit pour retrouver ce numéro :

annuaire = {"Alice": "06 12 34 56 78", "Bob": "07 98 76 54 32"}
print(annuaire["Bob"])
07 98 76 54 32

Dans les deux cas, on obtient le même numéro ; mais avec le dictionnaire, inutile de connaître sa position.

Un dictionnaire fonctionne sur ce principe : au lieu d’un indice numérique, on utilise une clé (par exemple un nom, un mot, un code) pour accéder à une valeur (un numéro de téléphone, une définition, une note).

Qu’est-ce qu’un dictionnaire ?

Un dictionnaire s’écrit entre accolades {}. Il est formé d’entrées, séparées par des virgules ; chaque entrée associe une clé et sa valeur, séparées par deux-points : clé: valeur.

eleve = {"nom": "Dupont", "prenom": "Marie", "age": 16}
print(eleve)
{'nom': 'Dupont', 'prenom': 'Marie', 'age': 16}

Ici, la clé "nom" est associée à la valeur "Dupont", la clé "prenom" à la valeur "Marie", et la clé "age" à la valeur 16. Les clés sont des chaînes de caractères ; les valeurs sont des chaînes de caractères et un entier.

Pour la lisibilité, on peut écrire une entrée par ligne :

annuaire = {"Alice": "06 12 34 56 78",
            "Bob": "07 98 76 54 32",
            "Charlie": "06 11 22 33 44"}
print(annuaire)
{'Alice': '06 12 34 56 78', 'Bob': '07 98 76 54 32', 'Charlie': '06 11 22 33 44'}

Un dictionnaire vide s’écrit avec deux accolades, sans rien entre elles :

d = {}
# ou
d = dict()

Lire une valeur avec sa clé

On accède à une valeur en écrivant le nom du dictionnaire, puis la clé entre crochets :

annuaire = {"Alice": "06 12 34 56 78",
            "Bob": "07 98 76 54 32",
            "Charlie": "06 11 22 33 44"}

print(annuaire["Alice"])    # 06 12 34 56 78
print(annuaire["Charlie"])  # 06 11 22 33 44

De même, avec la fiche de l’élève :

eleve = {"nom": "Dupont", "prenom": "Marie", "age": 16}
print(eleve["prenom"])
print(eleve["age"])
Marie
16

Question. Les entrées de eleve sont écrites dans un certain ordre. Que se passe-t-il si l’on écrit eleve[0] pour lire la première ?

Réponse

Python s’arrête avec une erreur de clé, KeyError : 0 n’est pas une clé de ce dictionnaire.

print(eleve[0])
KeyError: 0

Un dictionnaire n’a pas d’indices : on lit une valeur uniquement grâce à la clé qui lui correspond.

Une clé absente

Attention : si la clé n’existe pas, Python lève une erreur KeyError :

print(annuaire["Diana"])  # KeyError: 'Diana'

Pour éviter cette erreur, on peut utiliser la méthode get(), qui renvoie None (c’est-à-dire aucune valeur) ou une valeur par défaut si la clé est absente :

print(annuaire.get("Diana"))         # None
print(annuaire.get("Diana", "???"))  # ???
print(annuaire.get("Alice", "???"))  # 06 12 34 56 78

La valeur par défaut est souvent 0, par exemple pour la note d’un élève absent du dictionnaire :

notes = {"Lina": 15, "Tom": 12}
print(notes.get("Sami"))
print(notes.get("Sami", 0))
None
0

Question. Qu’affiche print(notes.get("Lina", 0)) ?

Réponse
15

La clé "Lina" existe : get() renvoie simplement sa valeur. La valeur par défaut ne sert que pour une clé absente.

Ajouter, modifier ou supprimer une entrée

Un dictionnaire se modifie, comme une liste. Pour ajouter un couple clé-valeur ou modifier une valeur existante, on utilise la même syntaxe :

eleve = {"nom": "Dupont", "prenom": "Marie"}

# Ajouter une nouvelle clé
eleve["classe"] = "1NSI"
print(eleve)

# Modifier une valeur existante
eleve["classe"] = "TNSI"
print(eleve)
{'nom': 'Dupont', 'prenom': 'Marie', 'classe': '1NSI'}
{'nom': 'Dupont', 'prenom': 'Marie', 'classe': 'TNSI'}

Si la clé existe déjà, la valeur est remplacée (un dictionnaire ne peut pas contenir deux fois la même clé).

On supprime un couple clé-valeur avec le mot-clé del :

eleve = {"nom": "Dupont", "prenom": "Marie", "classe": "1NSI"}
del eleve["classe"]
print(eleve)  # {'nom': 'Dupont', 'prenom': 'Marie'}
InstructionEffet sur le dictionnaire
eleve["classe"] = "1NSI"ajout d’une entrée : la clé "classe" est nouvelle
eleve["classe"] = "TNSI"modification : la clé "classe" existe déjà
del eleve["classe"]suppression de l’entrée, clé et valeur

À retenir : une clé nouvelle provoque un ajout, une clé existante provoque une modification.

Longueur et appartenance

La fonction len() renvoie le nombre de couples clé-valeur, c’est-à-dire le nombre d’entrées :

eleve = {"nom": "Dupont", "prenom": "Marie", "classe": "1NSI"}
print(len(eleve))  # 3

L’opérateur in teste si une clé est présente dans le dictionnaire :

print("nom" in eleve)     # True
print("age" in eleve)     # False
print("Dupont" in eleve)  # False (in teste les CLÉS, pas les valeurs)

"Dupont" est une valeur, et non une clé : sur un dictionnaire, in cherche seulement parmi les clés.

Parcourir un dictionnaire par ses clés

Par défaut, une boucle for sur un dictionnaire parcourt ses clés, dans l’ordre où les entrées ont été ajoutées :

eleve = {"nom": "Dupont", "prenom": "Marie", "classe": "1NSI"}

for cle in eleve:
    print(f"{cle} : {eleve[cle]}")
nom : Dupont
prenom : Marie
classe : 1NSI

À chaque tour, la variable cle reçoit une clé, et eleve[cle] donne la valeur qui lui est associée :

TourValeur de cleValeur associéeAffichage
1"nom""Dupont"nom : Dupont
2"prenom""Marie"prenom : Marie
3"classe""1NSI"classe : 1NSI

On peut aussi utiliser la méthode keys() pour être plus explicite ; elle donne les mêmes clés :

for cle in eleve.keys():
    print(cle)
nom
prenom
classe

Parcourir les valeurs et les couples

Parcours des valeurs

La méthode values() renvoie les valeurs, sans les clés :

for valeur in eleve.values():
    print(valeur)
Dupont
Marie
1NSI

Question. "Marie" in eleve donne False, car "Marie" n’est pas une clé. Comment tester si "Marie" fait partie des valeurs du dictionnaire ?

Réponse

Avec la méthode values(), le mot-clé in cherche parmi les valeurs :

print("Marie" in eleve.values())
True

Parcours des couples (clé, valeur)

La méthode items() renvoie les paires sous forme de tuples. Le déballage sépare chaque couple en deux variables, la clé et la valeur :

for cle, valeur in eleve.items():
    print(f"{cle} → {valeur}")
nom → Dupont
prenom → Marie
classe → 1NSI

Une liste de dictionnaires

En pratique, on combine souvent les dictionnaires et les listes. Par exemple, une classe d’élèves peut être représentée comme une liste de dictionnaires ; à chaque tour, la variable eleve contient un dictionnaire, et on lit ses valeurs avec les clés "prenom", "nom" et "moyenne" :

classe = [
    {"nom": "Dupont", "prenom": "Marie", "moyenne": 14.5},
    {"nom": "Martin", "prenom": "Alice", "moyenne": 16.0},
    {"nom": "Durand", "prenom": "Bob", "moyenne": 12.5}
]

# Afficher les noms et moyennes
for eleve in classe:
    print(f"{eleve['prenom']} {eleve['nom']} : {eleve['moyenne']}")
Marie Dupont : 14.5
Alice Martin : 16.0
Bob Durand : 12.5
# Calculer la moyenne de la classe
total = sum([e["moyenne"] for e in classe])
print(f"Moyenne de la classe : {total / len(classe)}")
Moyenne de la classe : 14.333333333333334

Question. Que vaut classe[1]["prenom"] ?

Réponse
print(classe[1]["prenom"])
Alice

classe[1] est l’élément d’indice 1 de la liste, c’est-à-dire le deuxième dictionnaire ; la clé "prenom" y donne la valeur "Alice". On écrit d’abord l’indice dans la liste, puis la clé dans le dictionnaire.

Avec une liste de tuples, ("Dupont", "Marie", 14.5), il faudrait se souvenir que la moyenne se trouve à l’indice 2 du tuple ; avec un dictionnaire, la clé "moyenne" dit ce que contient la valeur : le programme est plus lisible.

Le programme de NSI appelle p-uplet nommé un tel ensemble de valeurs repérées par des noms (les clés) plutôt que par des positions : c’est ce qu’un dictionnaire Python représente, par opposition au tuple, ou p-uplet, dont les éléments sont repérés par leur indice.

Des clés immuables

Les clés d’un dictionnaire doivent être de type immuable : entiers, chaînes de caractères ou tuples. Les listes et les dictionnaires, qui se modifient, ne peuvent pas servir de clés.

# Clés de types variés
d = {42: "un entier", "nom": "une chaîne", (0, 1): "un tuple"}
print(d[42])       # un entier
print(d[(0, 1)])   # un tuple
# Une liste comme clé → erreur
d = {[1, 2]: "interdit"}  # TypeError: unhashable type: 'list'

Exemple concret : pour stocker les cases d’un plateau de jeu, on utilise les coordonnées (ligne, colonne) comme clés :

plateau = {}
plateau[(0, 0)] = "tour"
plateau[(0, 1)] = "cavalier"
plateau[(3, 4)] = "pion"
print(plateau[(0, 0)])   # tour

Ce ne serait pas possible avec des listes [0, 0], car une liste ne peut pas être une clé de dictionnaire.

Des valeurs de tout type

Les valeurs n’ont aucune contrainte : elles peuvent être des entiers, des flottants, des chaînes de caractères, des listes, d’autres dictionnaires, etc.

fiche = {
    "nom": "Dupont",
    "notes": [15, 12, 18, 14],
    "adresse": {"rue": "10 rue des Lilas", "ville": "Lyon"}
}
print(fiche["notes"][2])            # 18
print(fiche["adresse"]["ville"])    # Lyon

On enchaîne deux paires de crochets : fiche["notes"] donne la liste des notes, puis [2] donne sa note d’indice 2 ; de même, fiche["adresse"] donne un dictionnaire, dans lequel la clé "ville" donne "Lyon".

Compter les apparitions

Une utilisation classique des dictionnaires consiste à compter combien de fois chaque élément apparaît, par exemple chaque lettre d’un mot. On part d’un dictionnaire vide ; pour chaque lettre, si elle est déjà une clé, on ajoute 1 à sa valeur, sinon on crée son entrée, avec la valeur 1.

mot = "radar"
compte = {}
for lettre in mot:
    if lettre in compte:
        compte[lettre] += 1
    else:
        compte[lettre] = 1
print(compte)

Question. Qu’affiche ce programme ?

Réponse
{'r': 2, 'a': 2, 'd': 1}
TourValeur de lettreDéjà une clé ?Contenu de compte après le tour
1'r'non{'r': 1}
2'a'non{'r': 1, 'a': 1}
3'd'non{'r': 1, 'a': 1, 'd': 1}
4'a'oui{'r': 1, 'a': 2, 'd': 1}
5'r'oui{'r': 2, 'a': 2, 'd': 1}

La méthode get() permet d’écrire ce test en une seule ligne : frequences.get(lettre, 0) renvoie 0 pour une lettre absente, et le calcul donne 1, comme avec le else.

# Compter les lettres d'un mot
mot = "abracadabra"
frequences = {}
for lettre in mot:
    frequences[lettre] = frequences.get(lettre, 0) + 1
print(frequences)  # {'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}

Construire un dictionnaire en compréhension

Comme les listes, les dictionnaires peuvent être créés par compréhension. Entre accolades, on écrit la clé, deux-points, la valeur, puis la boucle qui fournit les valeurs de la variable :

carres = {n: n**2 for n in range(6)}

Question. Que contient le dictionnaire carres ?

Réponse
print(carres)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Chaque entier de 0 à 5 devient une clé, associée à son carré.

Une compréhension transforme aussi une liste de tuples en dictionnaire, grâce au déballage :

eleves = [("Lina", 15), ("Tom", 12), ("Sami", 17)]
notes = {prenom: note for prenom, note in eleves}
print(notes)
print(notes["Tom"])
{'Lina': 15, 'Tom': 12, 'Sami': 17}
12

À retenir

  1. Un dictionnaire associe des clés à des valeurs, entre accolades : {"nom": "Dupont"}.
  2. On lit une valeur par sa clé, eleve["nom"] ; un dictionnaire n’a pas d’indices.
  3. notes.get("Sami", 0) évite l’erreur KeyError : get() renvoie None, ou la valeur par défaut donnée.
  4. eleve[cle] = valeur ajoute une entrée si la clé est nouvelle et modifie sa valeur si la clé existe ; del eleve[cle] supprime une entrée.
  5. "nom" in eleve cherche parmi les clés ; "Marie" in eleve.values(), parmi les valeurs.
  6. On parcourt les clés avec for cle in eleve, les valeurs avec values(), les couples avec items().
  7. Une clé est immuable (entier, chaîne de caractères, tuple) ; une valeur peut être de n’importe quel type.
  8. compte[lettre] = compte.get(lettre, 0) + 1 compte les apparitions de chaque élément.

Résumé

OpérationSyntaxeExemple
Création{clé: valeur, ...}{"nom": "Alice"}
Accèsd[clé]d["nom"] → "Alice"
Accès sûrd.get(clé, défaut)d.get("age", 0)
Ajout / modificationd[clé] = valeurd["age"] = 17
Suppressiondel d[clé]del d["age"]
Longueurlen(d)len(d) → 1
Appartenanceclé in d"nom" in d → True
Parcours clésfor k in d:
Parcours valeursfor v in d.values():
Parcours couplesfor k, v in d.items():