Tuples et Dictionnaires
Les tuples et les dictionnaires sont deux structures de données fondamentales en Python. Les tuples permettent de stocker des collections ordonnées et immuables, tandis que les dictionnaires associent des clés à des valeurs.
1. Les Tuples
Créer un tuple
Un tuple se crée avec des parenthèses ou avec la fonction tuple().
# Tuple littéral
coordonnees = (48.8566, 2.3522)
couleurs_rgb = (255, 128, 0)
jours = ("lundi", "mardi", "mercredi")
# Depuis une liste
nombres = tuple([1, 2, 3, 4, 5])
# Tuple vide
vide = ()
# Tuple avec un seul élément — la virgule est OBLIGATOIRE !
singleton = (42,)
print(type(singleton)) # <class 'tuple'>
# Sans virgule, ce n'est pas un tuple
pas_un_tuple = (42)
print(type(pas_un_tuple)) # <class 'int'>
Pour créer un tuple d'un seul élément, la virgule finale est obligatoire : (42,) et non (42).
Accéder aux éléments
Les tuples sont ordonnés : on accède aux éléments par leur index (commence à 0).
fruits = ("pomme", "banane", "cerise", "datte")
print(fruits[0]) # pomme
print(fruits[-1]) # datte (dernier élément)
print(fruits[1:3]) # ('banane', 'cerise') — slicing
# Longueur
print(len(fruits)) # 4
Tuples immuables
Un tuple ne peut pas être modifié après sa création. Toute tentative de modification lève une erreur.
point = (10, 20)
# point[0] = 15 # TypeError: 'tuple' object does not support item assignment
Déballage (unpacking)
Le déballage permet d'assigner chaque élément d'un tuple à une variable distincte.
coordonnees = (48.8566, 2.3522)
latitude, longitude = coordonnees
print(f"Latitude: {latitude}, Longitude: {longitude}")
# Déballage étendu avec *
premier, *milieu, dernier = (1, 2, 3, 4, 5)
print(premier) # 1
print(milieu) # [2, 3, 4]
print(dernier) # 5
# Échange de variables en une ligne
a, b = 10, 20
a, b = b, a
print(a, b) # 20 10
Méthodes des tuples
Les tuples disposent de deux méthodes principales :
notes = (15, 18, 12, 18, 10, 15)
print(notes.count(18)) # 2 — nombre d'occurrences de 18
print(notes.index(12)) # 2 — index de la première occurrence de 12
Quand utiliser un tuple plutôt qu'une liste ?
| Situation | Utiliser |
|---|---|
| Données fixes (coordonnées GPS, couleur RGB) | Tuple |
| Retour multiple d'une fonction | Tuple |
| Clé d'un dictionnaire | Tuple |
| Collection à modifier | Liste |
| Ordre de traitement variable | Liste |
# Bon usage des tuples
COULEURS = {
"rouge": (255, 0, 0),
"vert": (0, 255, 0),
"bleu": (0, 0, 255),
}
# Ligne d'une base de données (id, nom, age)
ligne_db = (1, "Alice", 30)
id_user, nom, age = ligne_db
Named tuples (mention rapide)
Le module collections fournit namedtuple pour créer des tuples dont les champs ont un nom.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x) # 10
print(p.y) # 20
print(p) # Point(x=10, y=20)
Exercice 1 — Créer un tuple et le déballer
Le déballage de tuple rend le code plus lisible que l'accès par index. Privilégiez nom, age = personne plutôt que nom = personne[0]; age = personne[1].
2. Les Dictionnaires
Un dictionnaire (dict) est une collection de paires clé : valeur. Les clés sont uniques et les valeurs peuvent être de n'importe quel type.
Créer un dictionnaire
# Dictionnaire litteral
etudiant = {
"nom": "Bob",
"age": 22,
"notes": [14, 16, 18],
}
# Avec dict()
config = dict(host="localhost", port=5432, debug=True)
# Dictionnaire vide
vide = {}
vide2 = dict()
Accéder aux valeurs
etudiant = {"nom": "Alice", "age": 30, "ville": "Lyon"}
# Accès direct — lève KeyError si la clé est absente
print(etudiant["nom"]) # Alice
# Accès sécurisé avec .get() — renvoie None (ou une valeur par défaut) si absent
print(etudiant.get("age")) # 30
print(etudiant.get("email")) # None
print(etudiant.get("email", "N/A")) # N/A
Ajouter et modifier
profil = {"nom": "Charlie", "age": 25}
# Ajouter une nouvelle clé
profil["email"] = "charlie@example.com"
# Modifier une valeur existante
profil["age"] = 26
print(profil)
# {'nom': 'Charlie', 'age': 26, 'email': 'charlie@example.com'}
Supprimer des entrées
inventaire = {"pommes": 10, "bananes": 5, "cerises": 20}
# del — lève KeyError si absent
del inventaire["bananes"]
# .pop() — renvoie la valeur supprimée, KeyError si absent sans défaut
nb_cerises = inventaire.pop("cerises")
print(nb_cerises) # 20
# .pop() avec valeur par défaut — sans KeyError
val = inventaire.pop("mangues", 0)
print(val) # 0
# Vider tout le dictionnaire
inventaire.clear()
print(inventaire) # {}
Méthodes principales
capitale = {"France": "Paris", "Italie": "Rome", "Espagne": "Madrid"}
# Clés, valeurs, paires
print(list(capitale.keys())) # ['France', 'Italie', 'Espagne']
print(list(capitale.values())) # ['Paris', 'Rome', 'Madrid']
print(list(capitale.items())) # [('France', 'Paris'), ...]
# Fusionner avec update()
capitale.update({"Allemagne": "Berlin", "France": "PARIS"})
# Copie superficielle
copie = capitale.copy()
Tester la présence d'une clé
config = {"debug": True, "version": "1.0"}
if "debug" in config:
print("Mode debug actif")
if "timeout" not in config:
print("Pas de timeout configuré")
Itérer sur un dictionnaire
notes = {"maths": 16, "physique": 14, "info": 18}
# Itérer sur les clés (défaut)
for matiere in notes:
print(matiere)
# Itérer sur les clés et valeurs
for matiere, note in notes.items():
print(f"{matiere}: {note}/20")
# Itérer sur les valeurs uniquement
for note in notes.values():
print(note)
Exercice 2 — Accès sécurisé avec .get()
Préférez toujours d.get("cle", valeur_defaut) à d["cle"] quand vous n'êtes pas certain que la clé existe. Cela évite les KeyError inattendues.
Exercice 3 — Itérer sur les paires clé/valeur
Utilisez toujours .items() quand vous avez besoin des clés ET des valeurs. C'est plus lisible et plus efficace que d'accéder à d[k] dans une boucle sur les clés.
Compréhensions de dictionnaire
Comme les listes en compréhension, les dictionnaires supportent une syntaxe compacte pour les construire.
# Doubler les valeurs
prix = {"pomme": 1.2, "banane": 0.8, "cerise": 3.5}
prix_doubles = {fruit: p * 2 for fruit, p in prix.items()}
print(prix_doubles)
# Filtrer — garder seulement les fruits à moins de 2 euros
prix_abordables = {f: p for f, p in prix.items() if p < 2}
print(prix_abordables)
# Inverser cles et valeurs
capitales = {"France": "Paris", "Italie": "Rome"}
inverse = {v: k for k, v in capitales.items()}
print(inverse) # {'Paris': 'France', 'Rome': 'Italie'}
# Construire depuis deux listes
noms = ["a", "b", "c"]
vals = [1, 2, 3]
d = {k: v for k, v in zip(noms, vals)}
print(d) # {'a': 1, 'b': 2, 'c': 3}
Exercice 4 — Compréhension de dictionnaire
Les compréhensions de dictionnaire sont puissantes mais ne pas abuser : si la logique est complexe, une boucle for classique est plus lisible.
Dictionnaires imbriqués
Un dictionnaire peut contenir d'autres dictionnaires comme valeurs.
etudiants = {
"alice": {
"age": 22,
"notes": {"maths": 16, "info": 18},
"ville": "Paris",
},
"bob": {
"age": 24,
"notes": {"maths": 12, "info": 15},
"ville": "Lyon",
},
}
# Acces imbriquE
print(etudiants["alice"]["notes"]["info"]) # 18
# Acces securise en cascade
note_physique = etudiants.get("alice", {}).get("notes", {}).get("physique", "N/A")
print(note_physique) # N/A
Exercice 5 — Accès dans un dictionnaire imbriqué
Pour les structures très imbriquées, envisagez d'utiliser des classes ou des dataclasses Python qui rendent l'accès aux attributs plus explicite et les erreurs plus claires.
Exercice 6 — Mettre à jour un dictionnaire
La méthode .update() permet de fusionner plusieurs clés en une seule opération. Elle est plus lisible que plusieurs affectations individuelles quand on met à jour plusieurs clés à la fois.
Dictionnaires et JSON
Les dictionnaires Python et le format JSON sont très proches. Le module json permet de convertir l'un en l'autre.
import json
# Dict Python -> chaine JSON
profil = {"nom": "Alice", "age": 30, "actif": True}
json_str = json.dumps(profil, indent=2, ensure_ascii=False)
print(json_str)
# {
# "nom": "Alice",
# "age": 30,
# "actif": true
# }
# Chaine JSON -> Dict Python
data = json.loads('{"nom": "Bob", "score": 42}')
print(data["nom"]) # Bob
print(type(data)) # <class 'dict'>