Dictionnaires imbriqués
Apprenez à créer, accéder, modifier, supprimer et parcourir des dictionnaires imbriqués en Python avec des exemples clairs et les meilleures pratiques.
Un dictionnaire imbriqué est un dictionnaire qui contient d'autres dictionnaires comme valeurs. Cela crée une structure de données hiérarchique (arborescente) idéale pour représenter des données groupées du monde réel — comme une collection de profils utilisateurs, un fichier de configuration ou une réponse d'API JSON.
Ce chapitre couvre :
- La création de dictionnaires imbriqués
- L'accès aux valeurs à n'importe quelle profondeur
- La modification et l'ajout d'entrées
- La suppression de clés et de sous-dictionnaires
- Le parcours de dictionnaires imbriqués
- L'utilisation de
.get()pour éviter lesKeyError - Le travail avec des données profondément imbriquées et le JSON
Création de dictionnaires imbriqués
Définissez un dictionnaire dont les valeurs sont elles-mêmes des dictionnaires :
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
}
print(people)
# {'person1': {'name': 'Alice', 'age': 30}, 'person2': {'name': 'Bob', 'age': 25}}Vous pouvez également construire un dictionnaire imbriqué de manière incrémentale :
people = {}
people["person1"] = {"name": "Alice", "age": 30}
people["person2"] = {"name": "Bob", "age": 25}
print(people["person1"]) # {'name': 'Alice', 'age': 30}Il n'y a pas de limite à la profondeur — une valeur interne peut elle-même être un dictionnaire imbriqué.
Accès aux valeurs d'un dictionnaire imbriqué
Enchaînez les accès entre crochets pour accéder à n'importe quel niveau :
Accès sécurisé avec .get()
Les accès enchaînés entre crochets lèvent une KeyError si une clé est absente. Utilisez .get() pour renvoyer une valeur par défaut à la place :
people = {
"person1": {"name": "Alice", "age": 30},
}
# Safe: returns None if "person3" does not exist
print(people.get("person3", {}).get("name", "Unknown")) # Unknown
# Risky: raises KeyError
# print(people["person3"]["name"])Le motif .get(outer_key, {}).get(inner_key, default) est la façon idiomatique de lire des données imbriquées optionnelles sans bloc try/except.
Modification des valeurs d'un dictionnaire imbriqué
Affectez directement via la chaîne de clés :
Ajout de nouveaux sous-dictionnaires
Affectez un nouveau littéral de dictionnaire à une nouvelle clé externe :
Utiliser setdefault() pour n'ajouter qu'en cas d'absence
setdefault() insère une clé avec une valeur par défaut uniquement si elle n'existe pas encore — utile lors de la construction de dictionnaires imbriqués à partir d'un flux de données :
scores = {}
for student, subject, grade in [
("Alice", "math", 90),
("Alice", "english", 85),
("Bob", "math", 78),
]:
scores.setdefault(student, {})[subject] = grade
print(scores)
# {'Alice': {'math': 90, 'english': 85}, 'Bob': {'math': 78}}Suppression de clés et de sous-dictionnaires
Utilisez del pour supprimer une clé (et sa valeur) à n'importe quel niveau :
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
"person3": {"name": "Carol", "age": 40},
}
del people["person2"]["age"] # remove one key from an inner dict
del people["person3"] # remove an entire sub-dictionary
print(people)
# {'person1': {'name': 'Alice', 'age': 30}, 'person2': {'name': 'Bob'}}Utilisez .pop() si vous avez également besoin de la valeur supprimée :
removed = people["person1"].pop("age", None)
print(removed) # 30
print(people["person1"]) # {'name': 'Alice'}Parcours de dictionnaires imbriqués
Boucle sur les clés externes et les éléments internes
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
}
for person_id, details in people.items():
print(f"{person_id}:")
for key, value in details.items():
print(f" {key}: {value}")Sortie :
person1:
name: Alice
age: 30
person2:
name: Bob
age: 25Aplatir un dictionnaire imbriqué en liste d'enregistrements
Un motif courant lors de la préparation de données pour le traitement :
people = {
"person1": {"name": "Alice", "age": 30},
"person2": {"name": "Bob", "age": 25},
}
records = [
{"id": pid, **info}
for pid, info in people.items()
]
print(records)
# [{'id': 'person1', 'name': 'Alice', 'age': 30},
# {'id': 'person2', 'name': 'Bob', 'age': 25}]Dictionnaires profondément imbriqués
Python n'impose aucune limite à la profondeur d'imbrication. Voici un exemple à trois niveaux représentant la structure des départements d'une entreprise :
company = {
"engineering": {
"frontend": {
"lead": "Alice",
"headcount": 5,
},
"backend": {
"lead": "Bob",
"headcount": 8,
},
},
"marketing": {
"content": {
"lead": "Carol",
"headcount": 3,
},
},
}
# Access three levels deep
print(company["engineering"]["backend"]["lead"]) # Bob
# Iterate two levels and collect leads
leads = [
dept_data["lead"]
for dept_data in (
team
for teams in company.values()
for team in teams.values()
)
]
print(leads) # ['Alice', 'Bob', 'Carol']Lorsque vous lisez des clés profondes qui peuvent être absentes, enchaînez les appels .get() :
lead = company.get("hr", {}).get("recruitment", {}).get("lead", "Not assigned")
print(lead) # Not assignedDictionnaires imbriqués et JSON
Les objets JSON se mappent directement aux dictionnaires imbriqués Python. Le module json permet la conversion entre les deux :
import json
data = {
"users": {
"u1": {"name": "Alice", "active": True},
"u2": {"name": "Bob", "active": False},
}
}
# Serialize to JSON string
json_str = json.dumps(data, indent=2)
print(json_str)
# Deserialize back to a nested dict
restored = json.loads(json_str)
print(restored["users"]["u1"]["name"]) # AliceC'est le flux de travail typique lors de la consommation d'API REST ou de la lecture de fichiers de configuration.
Pièges courants
Le piège de la référence partagée. Si vous copiez un dictionnaire interne par référence puis le modifiez, l'original et la copie changent tous les deux :
original = {"a": {"x": 1}}
shallow = original.copy() # copies only the outer dict
shallow["a"]["x"] = 99
print(original["a"]["x"]) # 99 ← original is affected!Utilisez copy.deepcopy() lorsque vous avez besoin d'une copie totalement indépendante :
import copy
original = {"a": {"x": 1}}
deep = copy.deepcopy(original)
deep["a"]["x"] = 99
print(original["a"]["x"]) # 1 ← original is safeConsultez le chapitre Copier des dictionnaires pour une comparaison complète des copies superficielles et profondes.
KeyError sur des clés intermédiaires manquantes. Écrire d["a"]["b"] = 1 lève une KeyError si "a" n'existe pas encore. Utilisez setdefault ou collections.defaultdict pour créer automatiquement les niveaux intermédiaires.
Référence rapide
| Tâche | Syntaxe |
|---|---|
| Accéder à une valeur interne | d["outer"]["inner"] |
| Accès sécurisé | d.get("outer", {}).get("inner", default) |
| Ajouter / mettre à jour une clé interne | d["outer"]["inner"] = value |
| Ajouter un nouveau sous-dictionnaire | d["new_key"] = {...} |
| Supprimer une clé interne | del d["outer"]["inner"] |
| Supprimer un sous-dictionnaire | del d["outer"] |
| Parcourir toutes les entrées | for k, v in d.items(): for ik, iv in v.items(): |
| Copie profonde | import copy; copy.deepcopy(d) |