W3docs

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 les KeyError
  • 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 :

python— editable, runs on the server

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 :

python— editable, runs on the server

Ajout de nouveaux sous-dictionnaires

Affectez un nouveau littéral de dictionnaire à une nouvelle clé externe :

python— editable, runs on the server

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: 25

Aplatir 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 assigned

Dictionnaires 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"])  # Alice

C'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 safe

Consultez 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âcheSyntaxe
Accéder à une valeur interned["outer"]["inner"]
Accès sécuriséd.get("outer", {}).get("inner", default)
Ajouter / mettre à jour une clé interned["outer"]["inner"] = value
Ajouter un nouveau sous-dictionnaired["new_key"] = {...}
Supprimer une clé internedel d["outer"]["inner"]
Supprimer un sous-dictionnairedel d["outer"]
Parcourir toutes les entréesfor k, v in d.items(): for ik, iv in v.items():
Copie profondeimport copy; copy.deepcopy(d)

Pratique

Pratique
Which method safely reads a missing key from a nested dict without raising a KeyError?
Which method safely reads a missing key from a nested dict without raising a KeyError?
Was this page helpful?