Bases

Dictionnaires en Python (dict) : création, méthodes, parcours, tri et frozendict

Mis à jour: · Skillaria.Top

Un dictionnaire en Python (dict) est une collection modifiable de paires « clé — valeur » qui retrouve une valeur par sa clé presque instantanément ; il se crée avec des accolades, comme {"café": 250}, ou avec la fonction dict(). Les clés sont uniques et doivent être hachables, l'ordre d'insertion est conservé depuis Python 3.7, et Python 3.15 ajoute une version immuable intégrée : frozendict.

Le dictionnaire en Python (dict) est une collection de paires « clé — valeur » dans laquelle on retrouve une valeur par sa clé presque instantanément, quel que soit le nombre d'entrées. Pour calculer des dépenses par catégorie, conserver des réglages ou rechercher rapidement un utilisateur par son identifiant, on utilise un dictionnaire. Voici l'essentiel : création, méthodes, parcours, tri, fusion, et la nouveauté de Python 3.15, frozendict.

Qu'est-ce qu'un dictionnaire en Python

Un dictionnaire stocke des paires dont la clé est unique : si vous écrivez une valeur pour une clé existante, l'ancienne est remplacée. En interne, c'est une table de hachage, si bien que la recherche, l'ajout et la suppression par clé se font en temps moyen constant, sans parcours.

Une clé doit être un objet hachable : chaîne, nombre, tuple de valeurs non modifiables. Une liste ne peut pas servir de clé et provoque TypeError: unhashable type: 'list'. Les valeurs, en revanche, peuvent être n'importe quoi, y compris d'autres dictionnaires et des listes.

Depuis Python 3.7, le dictionnaire conserve l'ordre d'insertion : en le parcourant, on obtient les clés dans l'ordre où elles ont été ajoutées.

Comment créer un dictionnaire

Il existe plusieurs façons de créer un dictionnaire, et toutes se rencontrent dans le code réel.

depenses = {"Alimentation": 1200, "Taxi": 450}  # littéral
vide = {}                                       # dictionnaire vide
aussi_vide = dict()                             # la même chose avec la fonction dict
utilisateur = dict(nom="Anna", age=30)          # arguments nommés
paires = dict([("a", 1), ("b", 2)])             # à partir d'une liste de paires
cles = dict.fromkeys(["x", "y"], 0)             # {'x': 0, 'y': 0}

Attention : les accolades vides {} créent un dictionnaire vide, et non un ensemble. Un ensemble vide s'obtient uniquement avec set().

Pour construire un dictionnaire à partir de deux listes, la fonction zip est pratique :

noms = ["Alimentation", "Taxi", "Cinéma"]
sommes = [1200, 450, 600]
depenses = dict(zip(noms, sommes))
print(depenses)   # {'Alimentation': 1200, 'Taxi': 450, 'Cinéma': 600}

Accéder aux valeurs : d[k] et get

On lit une valeur entre crochets. Si la clé n'existe pas, Python lève KeyError. Pour éviter cette erreur, utilisez la méthode get : elle renvoie None, ou la valeur par défaut que vous indiquez.

depenses = {"Alimentation": 1200}
print(depenses["Alimentation"])          # 1200
print(depenses.get("Cinéma"))            # None
print(depenses.get("Cinéma", 0))         # 0
depenses["Cinéma"]                       # KeyError: 'Cinéma'

Pour savoir si une clé existe, utilisez l'opérateur in : "Alimentation" in depenses renvoie True. Il teste les clés, et non les valeurs ; pour les valeurs, écrivez 1200 in depenses.values().

Ajouter, modifier et supprimer

Ajouter ou mettre à jour une entrée tient en une ligne d'affectation. Pour les comptages, l'association avec get est très pratique :

depenses = {}
for categorie, montant in [("Alimentation", 250), ("Taxi", 300), ("Alimentation", 400)]:
    depenses[categorie] = depenses.get(categorie, 0) + montant
print(depenses)   # {'Alimentation': 650, 'Taxi': 300}

On supprime une clé avec del d[k] (qui lève KeyError si la clé est absente), ou avec d.pop(k, valeur_par_defaut), qui renvoie en plus la valeur supprimée. Pour vider le dictionnaire entièrement, utilisez d.clear(). Sa longueur, c'est-à-dire le nombre de paires, s'obtient avec len(d).

Méthodes des dictionnaires : aide-mémoire

MéthodeCe qu'elle fait
get(k, defaut)valeur de la clé, ou defaut sans erreur
setdefault(k, defaut)renvoie la valeur ; si la clé est absente, écrit d'abord defaut
update(autre)ajoute et écrase les paires d'un autre dictionnaire
pop(k, defaut)supprime la clé et renvoie sa valeur
popitem()supprime et renvoie la dernière paire ajoutée
keys(), values(), items()vues sur les clés, les valeurs et les paires
copy()copie superficielle
clear()vide le dictionnaire
fromkeys(cles, valeur)nouveau dictionnaire avec la même valeur partout

setdefault : remplir un dictionnaire de listes

La méthode setdefault est utile quand les valeurs sont des listes et qu'il faut regrouper :

groupes = {}
for article, cat in [("café", "Alimentation"), ("métro", "Transport"), ("pizza", "Alimentation")]:
    groupes.setdefault(cat, []).append(article)
print(groupes)   # {'Alimentation': ['café', 'pizza'], 'Transport': ['métro']}

update : mettre un dictionnaire à jour

update modifie le dictionnaire sur place : les nouvelles clés sont ajoutées, les clés existantes sont écrasées.

config = {"debug": False, "langue": "fr"}
config.update({"debug": True, "theme": "sombre"})
print(config)   # {'debug': True, 'langue': 'fr', 'theme': 'sombre'}

defaultdict : dictionnaire avec valeur par défaut

collections.defaultdict est une sous-classe de dict qui crée elle-même la valeur, à l'aide d'une fabrique, lorsqu'on accède à une clé absente. Le code de comptage et de regroupement devient plus court.

from collections import defaultdict

depenses = defaultdict(int)
for categorie, montant in [("Alimentation", 250), ("Taxi", 300), ("Alimentation", 400)]:
    depenses[categorie] += montant
print(dict(depenses))   # {'Alimentation': 650, 'Taxi': 300}

groupes = defaultdict(list)
groupes["Alimentation"].append("café")

Pour un simple comptage d'occurrences, il existe aussi collections.Counter : Counter(["a", "b", "a"]) donne Counter({'a': 2, 'b': 1}).

Parcourir un dictionnaire avec for

Une boucle for sur un dictionnaire porte par défaut sur les clés. Pour obtenir à la fois la clé et la valeur, parcourez items() : c'est le cas le plus courant.

depenses = {"Alimentation": 650, "Taxi": 300}

for categorie in depenses:           # clés
    print(categorie)

for montant in depenses.values():    # valeurs
    print(montant)

for categorie, montant in depenses.items():   # paires
    print(f"{categorie} : {montant} €")

On ne peut pas changer la taille d'un dictionnaire pendant son parcours : vous obtiendriez RuntimeError: dictionary changed size during iteration. Pour supprimer une partie des clés, parcourez une copie : for k in list(d):.

Afficher un dictionnaire

print(d) affiche le dictionnaire sur une seule ligne. Pour un dictionnaire volumineux ou imbriqué, le module pprint ou json.dumps(d, ensure_ascii=False, indent=2) est plus lisible : les données sont indentées et les accents ne sont pas échappés.

Trier un dictionnaire

Un dictionnaire ne se trie pas sur place : il n'a pas de méthode sort. Trier un dictionnaire revient à créer un nouveau dictionnaire à partir de paires triées avec sorted.

depenses = {"Taxi": 300, "Alimentation": 650, "Cinéma": 120}

par_cle = dict(sorted(depenses.items()))
print(par_cle)     # {'Alimentation': 650, 'Cinéma': 120, 'Taxi': 300}

par_valeur = dict(sorted(depenses.items(), key=lambda p: p[1], reverse=True))
print(par_valeur)  # {'Alimentation': 650, 'Taxi': 300, 'Cinéma': 120}

Si vous ne voulez que le top N des catégories, ne reconvertissez pas le résultat en dictionnaire : sorted(depenses.items(), key=lambda p: p[1], reverse=True)[:2] renvoie une liste de paires.

Pour trier une liste de dictionnaires selon un champ, écrivez : sorted(utilisateurs, key=lambda u: u["age"]).

Fusionner et additionner des dictionnaires

Depuis Python 3.9, les dictionnaires se fusionnent avec l'opérateur |, et |= met à jour un dictionnaire sur place. En cas de clés communes, c'est l'opérande de droite qui l'emporte.

a = {"x": 1, "y": 2}
b = {"y": 20, "z": 3}
print(a | b)          # {'x': 1, 'y': 20, 'z': 3}
print({**a, **b})     # la même chose avec la décompression
a |= b                # équivalent de a.update(b)

Attention : a + b ne fonctionne pas pour les dictionnaires et provoque TypeError. Si vous voulez justement additionner les valeurs des clés communes, utilisez Counter : Counter(a) + Counter(b).

Décomposer un dictionnaire

Deux astérisques ** décomposent un dictionnaire en arguments nommés d'une fonction, ou dans un autre dictionnaire :

def saluer(nom, ville):
    return f"{nom} de {ville}"

donnees = {"nom": "Anna", "ville": "Kazan"}
print(saluer(**donnees))   # Anna de Kazan

Compréhension de dictionnaire (dict comprehension)

La compréhension de dictionnaire construit un dictionnaire en une ligne à partir de n'importe quelle séquence :

carres = {n: n * n for n in range(5)}
print(carres)   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

grands = {k: v for k, v in depenses.items() if v > 200}

inverse = {v: k for k, v in {"a": 1, "b": 2}.items()}
print(inverse)  # {1: 'a', 2: 'b'}

Le dernier exemple montre comment inverser un dictionnaire en échangeant clés et valeurs. Cela fonctionne si les valeurs sont uniques et hachables ; sinon, certaines paires disparaîtront.

Dictionnaires imbriqués

Une valeur peut être un autre dictionnaire : c'est ainsi qu'on décrit des structures comme les réponses JSON d'une API, ou un dictionnaire de dictionnaires d'utilisateurs.

utilisateurs = {
    101: {"nom": "Anna", "competences": ["python", "sql"]},
    102: {"nom": "Oleg", "competences": ["go"]},
}
print(utilisateurs[101]["competences"][0])            # python
print(utilisateurs.get(103, {}).get("nom"))           # None, sans KeyError

Copier un dictionnaire : copie et second nom

L'instruction b = a ne copie pas le dictionnaire : elle donne un second nom au même objet. Si vous modifiez b, les changements apparaissent aussi dans a. Il en va de même lorsqu'on passe un dictionnaire à une fonction : celle-ci reçoit une référence vers l'objet commun et peut le modifier sans prévenir.

import copy

a = {"limites": [0, 500]}
b = a.copy()               # copie superficielle
b["limites"].append(1000)  # la liste imbriquée est commune !
print(a)                   # {'limites': [0, 500, 1000]}

c = copy.deepcopy(a)       # copie complète et indépendante

Comparer des dictionnaires

L'opérateur == compare les dictionnaires par leur contenu : ils sont égaux si toutes les paires coïncident. L'ordre des clés n'est pas pris en compte : {"a": 1, "b": 2} == {"b": 2, "a": 1} renvoie True. Pour trouver les clés communes, utilisez les opérations ensemblistes sur les vues : a.keys() & b.keys().

Dictionnaire typé : annotations

L'annotation d'un dictionnaire s'écrit dict[str, int]. Si le dictionnaire a un ensemble fixe de champs de types différents, TypedDict du module typing est pratique :

from typing import TypedDict

class Utilisateur(TypedDict):
    nom: str
    age: int

u: Utilisateur = {"nom": "Anna", "age": 30}

Les annotations ne sont pas vérifiées à l'exécution ; ce sont les IDE et les analyseurs comme mypy qui les exploitent.

Dictionnaire immuable : frozendict dans Python 3.15

Python 3.15 introduit le type intégré frozendict (PEP 814) : aucun import n'est nécessaire, et toute tentative de modification lève immédiatement TypeError. Auparavant, il fallait imiter un dictionnaire immuable avec un wrapper du module types ou avec un paquet tiers. C'est exactement ce qu'il faut pour des réglages communs qu'aucune fonction ne doit modifier discrètement.

config = frozendict(montant_min=0, montant_max=500)
config["montant_max"] = 1000
# TypeError: 'frozendict' object does not support item assignment

strict = config | {"montant_max": 300}   # nouveau frozendict, l'original reste intact
cache = {config: "rapport de mai"}      # hachable : peut servir de clé

Points importants, selon le cours :

  • frozendict hérite de object, et non de dict : isinstance(cfg, dict) renvoie False. Pour vérifier « n'importe quel dictionnaire », utilisez collections.abc.Mapping ou isinstance(x, (dict, frozendict)).
  • Il est hachable seulement si ses clés et ses valeurs le sont : frozendict(a=[1]) se crée, mais hash() échoue. L'immuabilité est superficielle, comme celle d'un tuple.
  • L'ordre est conservé, mais == ne le prend pas en compte.
  • json.dumps, pickle et copy savent gérer les frozendict.

Erreurs typiques

  • KeyError à la lecture — utilisez get ou un test in.
  • Une liste utilisée comme clé — transformez-la en tuple : d[tuple(liste)].
  • Modification du dictionnaire pendant une boucle — parcourez list(d).
  • Attendre une copie après une affectation — faites copy() ou deepcopy.
  • {} à la place d'un ensemble vide — cela crée un dictionnaire vide.

En bref

Le dictionnaire est la structure de données principale de Python : recherche rapide par clé, ordre d'insertion conservé, méthodes pratiques get, setdefault, update, parcours par items(), tri avec sorted et fusion avec l'opérateur |. Pensez à la copie et aux clés hachables, et pour les réglages en Python 3.15, prenez frozendict. Dictionnaires, listes, tuples et ensembles sont mis en pratique dans le cours sur Python, à travers un suivi de dépenses.

Questions fréquentes

Peut-on stocker des valeurs de types différents dans un dictionnaire ?

Oui, les valeurs peuvent être variées dans un même dictionnaire : nombres, chaînes, listes, autres dictionnaires. La seule contrainte porte sur les clés, qui doivent être hachables.

Comment connaître le nombre d'éléments d'un dictionnaire ?

La fonction len(d) renvoie le nombre de paires clé — valeur. Pour un dictionnaire vide, elle renvoie 0, et un dictionnaire vide est considéré comme faux dans une condition if.

Quelle est la différence entre dict et defaultdict ?

defaultdict est une sous-classe de dict qui, pour une clé absente, ne lève pas KeyError mais crée la valeur par une fabrique, comme int ou list. Pour le reste, il se comporte comme un dictionnaire ordinaire.

Comment obtenir une clé à partir d'une valeur ?

Il n'existe pas de méthode directe : il faut parcourir le dictionnaire, par exemple avec next((k for k, v in d.items() if v == valeur), None). Si la recherche est fréquente, construisez plutôt un dictionnaire inverse avec {v: k for k, v in d.items()}.

Comment enregistrer un dictionnaire dans un fichier ?

Le plus souvent avec le module json : json.dump(d, f, ensure_ascii=False, indent=2) dans un fichier ouvert en écriture, puis json.load(f) pour le relire. Les clés deviennent alors des chaînes de caractères.

Apprenez ce sujet en vidéo

Ce sujet est traité en détail avec de la pratique dans le cours « Python 3.15: от новичка до профи ».

Voir le cours