09 - Tuples
Exercice 1 : QCM – vérification des prérequis
Pour chaque question, une seule réponse est correcte.
1. Quelle est la différence fondamentale entre une liste et un tuple en Python ?
- A. Un tuple ne peut contenir que des entiers
- B. Un tuple est immutable (non modifiable après création)
- C. Un tuple est plus lent qu’une liste
- D. Un tuple ne peut pas contenir de doublons
Correction
Réponse : B. Un tuple, une fois créé, ne peut plus être modifié : on ne peut ni ajouter, ni supprimer, ni remplacer un élément. C’est la propriété d’immutabilité.
- A est faux : un tuple peut contenir n’importe quel type (
int,str,float, d’autres tuples, etc.). - C est faux : c’est l’inverse, un tuple est légèrement plus rapide qu’une liste.
- D est faux : un tuple peut contenir des doublons, comme
(1, 2, 1).
2. Parmi les expressions suivantes, laquelle crée un tuple contenant un seul élément ?
- A.
(42) - B.
(42,) - C.
[42] - D.
{42}
Correction
Réponse : B. Pour créer un tuple à un seul élément, il faut ajouter une virgule après l’élément : (42,).
- A est faux :
(42)est simplement l’entier 42 entre parenthèses (les parenthèses servent ici au regroupement, pas à la création d’un tuple).type((42))renvoieint. - C est faux :
[42]crée une liste à un élément. - D est faux :
{42}crée un ensemble (set) à un élément.
3. Que se passe-t-il si on exécute T[0] = 5 avec T = (1, 2, 3) ?
- A. Le tuple devient
(5, 2, 3) - B. Python crée un nouveau tuple
(5, 2, 3) - C. Python lève une erreur
TypeError - D. Python lève une erreur
IndexError
Correction
Réponse : C. L’affectation par indice est interdite sur un tuple car il est immutable. Python lève l’erreur TypeError: 'tuple' object does not support item assignment.
- A est faux : le tuple ne peut pas être modifié.
- B est faux : Python ne crée pas automatiquement un nouveau tuple.
- D est faux : l’indice 0 existe bien ; c’est l’opération d’écriture qui est interdite, pas la lecture.
4. Que renvoie la fonction suivante ?
def f():
return 3, 7
- A. L’entier 3 puis l’entier 7
- B. La chaîne
"3, 7" - C. Le tuple
(3, 7) - D. Une erreur car
returnne peut renvoyer qu’une valeur
Correction
Réponse : C. L’expression 3, 7 crée un tuple (3, 7). Une fonction peut renvoyer un tuple, ce qui permet de renvoyer plusieurs valeurs en une seule instruction return.
- A est faux : Python ne renvoie pas les valeurs « l’une après l’autre ».
- B est faux : il n’y a aucune conversion en chaîne.
- D est faux :
returnrenvoie un seul objet, ici le tuple(3, 7).
Exercice 2 : exemple travaillé – déballage et fonctions à valeurs multiples
Problème : écrire une fonction qui renvoie le quotient et le reste de la division euclidienne, puis utiliser le déballage pour récupérer les deux résultats.
Étape 1. Écriture de la fonction :
def division(a, b):
"""Renvoie le quotient et le reste de la division de a par b.
Paramètres :
a (int) : dividende (>= 0)
b (int) : diviseur (> 0)
Retour :
tuple : (quotient, reste)
"""
return (a // b, a % b)
Étape 2. Appel avec déballage :
q, r = division(17, 5)
print(f"17 = 5 × {q} + {r}") # 17 = 5 × 3 + 2
Étape 3. Vérification :
assert division(17, 5) == (3, 2)
assert division(20, 4) == (5, 0)
assert division(7, 10) == (0, 7)
Points clés :
return (a // b, a % b)renvoie un tuple de deux éléments.q, r = division(17, 5)utilise le déballage : chaque variable reçoit un élément du tuple.- Le nombre de variables à gauche doit correspondre exactement au nombre d’éléments du tuple.
Exercice 3 : manipulations guidées
3.1 Création et accès
Prévoir le résultat de chaque instruction, puis vérifier en Python :
a = (1, 2, 3)
b = 1, 2, 3
c = (1)
d = (1,)
e = tuple([1, 2])
f = ()
- Quel est le type de chacune de ces variables ?
- Que vaut
a == b? - Que vaut
a[1]? Eta[-1]?
Correction
a = (1, 2, 3) # tuple
b = 1, 2, 3 # tuple (les parenthèses sont facultatives)
c = (1) # int ! Les parenthèses ne suffisent pas.
d = (1,) # tuple (la virgule fait le tuple)
e = tuple([1, 2]) # tuple (conversion depuis une liste)
f = () # tuple vide
print(type(a)) # <class 'tuple'>
print(type(b)) # <class 'tuple'>
print(type(c)) # <class 'int'>
print(type(d)) # <class 'tuple'>
print(type(e)) # <class 'tuple'>
print(type(f)) # <class 'tuple'>
print(a == b) # True
print(a[1]) # 2
print(a[-1]) # 3
Piège classique : c = (1) ne crée pas un tuple mais un entier. Il faut écrire c = (1,) pour obtenir un tuple à un élément.
3.2 Déballage
Compléter le code suivant pour afficher les coordonnées d’un point :
point = (4.5, -2.3)
___, ___ = point
print(f"x = {___}, y = {___}")
Correction
point = (4.5, -2.3)
x, y = point
print(f"x = {x}, y = {y}")
# x = 4.5, y = -2.3
Exercice 4 : tuples et géométrie (mathématiques)
On représente un point du plan par un tuple (x, y).
Écrire une fonction
milieu(A, B)qui prend deux points et renvoie le tuple des coordonnées du milieu du segment $[AB]$.Rappel : $M = \left(\dfrac{x_A + x_B}{2},;, \dfrac{y_A + y_B}{2}\right)$
Écrire une fonction
distance(A, B)qui calcule la distance entre deux points.Rappel : $AB = \sqrt{(x_B - x_A)^2 + (y_B - y_A)^2}$
Tester avec $A(1,;, 2)$ et $B(5,;, 8)$.
Correction
import math
def milieu(A, B):
"""Renvoie le milieu du segment [AB]."""
xA, yA = A
xB, yB = B
return ((xA + xB) / 2, (yA + yB) / 2)
def distance(A, B):
"""Calcule la distance entre A et B."""
xA, yA = A
xB, yB = B
return round(math.sqrt((xB - xA) ** 2 + (yB - yA) ** 2), 2)
A = (1, 2)
B = (5, 8)
print(f"Milieu : {milieu(A, B)}") # (3.0, 5.0)
print(f"Distance : {distance(A, B)}") # 7.21
assert milieu((1, 2), (5, 8)) == (3.0, 5.0)
assert milieu((0, 0), (4, 6)) == (2.0, 3.0)
assert distance((0, 0), (3, 4)) == 5.0
print("Tests OK")
Point clé : le déballage xA, yA = A permet d’accéder directement aux coordonnées sans écrire A[0] et A[1], ce qui rend le code plus lisible.
Exercice 5 : tuples et données structurées (sport)
On représente les résultats d’une compétition de natation par une liste de tuples (nom, temps_en_secondes) :
resultats = [
("Alice", 28.4),
("Bob", 25.1),
("Clara", 27.8),
("David", 24.9),
("Eva", 26.3),
]
- Écrire une fonction
gagnant(resultats)qui renvoie le nom du nageur ayant le meilleur temps (le plus petit). - Écrire une fonction
podium(resultats)qui renvoie un tuple de trois noms(premier, deuxième, troisième)correspondant aux trois meilleurs temps. Indication : trier la liste par temps croissant, puis extraire les trois premiers noms. - Écrire une fonction
ecart(resultats)qui renvoie l’écart en secondes entre le meilleur et le pire temps.
Correction
def gagnant(resultats):
"""Renvoie le nom du nageur le plus rapide."""
meilleur = resultats[0]
for nom, temps in resultats:
if temps < meilleur[1]:
meilleur = (nom, temps)
return meilleur[0]
def podium(resultats):
"""Renvoie le tuple (1er, 2e, 3e) par temps croissant."""
# Tri par insertion sur le temps (2e élément du tuple)
tri = list(resultats) # copie pour ne pas modifier l'original
for i in range(1, len(tri)):
en_cours = tri[i]
j = i
while j > 0 and tri[j - 1][1] > en_cours[1]:
tri[j] = tri[j - 1]
j -= 1
tri[j] = en_cours
return (tri[0][0], tri[1][0], tri[2][0])
def ecart(resultats):
"""Renvoie l'écart entre le meilleur et le pire temps."""
temps_min = resultats[0][1]
temps_max = resultats[0][1]
for _, temps in resultats:
if temps < temps_min:
temps_min = temps
if temps > temps_max:
temps_max = temps
return round(temps_max - temps_min, 1)
resultats = [
("Alice", 28.4),
("Bob", 25.1),
("Clara", 27.8),
("David", 24.9),
("Eva", 26.3),
]
print(f"Gagnant : {gagnant(resultats)}") # David
print(f"Podium : {podium(resultats)}") # ('David', 'Bob', 'Eva')
print(f"Écart : {ecart(resultats)} s") # 3.5 s
Point clé : les tuples permettent de structurer des données hétérogènes (ici un nom et un temps). On accède au nom avec t[0] et au temps avec t[1], ou par déballage nom, temps = t.
Exercice 6 : tuples comme clés de dictionnaire (géographie)
Les tuples, étant immutables, peuvent servir de clés de dictionnaire. On utilise cette propriété pour associer des données à des coordonnées GPS :
villes = {
(48.86, 2.35): "Paris",
(43.30, 5.37): "Marseille",
(45.76, 4.84): "Lyon",
(43.60, 1.44): "Toulouse",
}
- Comment accéder au nom de la ville située aux coordonnées
(45.76, 4.84)? - Écrire une fonction
ville_plus_proche(lat, lon, villes)qui, étant donné une latitude et une longitude, renvoie le nom de la ville la plus proche (en utilisant la distance euclidienne comme approximation). - Tester avec les coordonnées
(44.0, 3.0). Quelle est la ville la plus proche ?
Correction
import math
villes = {
(48.86, 2.35): "Paris",
(43.30, 5.37): "Marseille",
(45.76, 4.84): "Lyon",
(43.60, 1.44): "Toulouse",
}
# 1.
print(villes[(45.76, 4.84)]) # Lyon
# 2.
def ville_plus_proche(lat, lon, villes):
"""Renvoie le nom de la ville la plus proche."""
plus_proche = None
dist_min = float('inf')
for (lat_v, lon_v), nom in villes.items():
d = math.sqrt((lat - lat_v) ** 2 + (lon - lon_v) ** 2)
if d < dist_min:
dist_min = d
plus_proche = nom
return plus_proche
# 3.
print(ville_plus_proche(44.0, 3.0, villes)) # Toulouse
Remarque : la distance euclidienne sur les coordonnées GPS n’est qu’une approximation (la Terre n’est pas plate). Pour un calcul exact, il faudrait utiliser la formule de Haversine (hors programme).
Exercice 7 : synthèse – statistiques sportives
On enregistre les performances de plusieurs athlètes lors d’un championnat d’athlétisme sous forme d’une liste de tuples (nom, épreuve, performance). La performance est en secondes pour les courses et en mètres pour les lancers.
courses = [
("Léa", "100m", 12.4),
("Karim", "100m", 11.8),
("Inès", "100m", 12.1),
("Théo", "100m", 11.5),
("Salma", "100m", 12.7),
]
Écrire une fonction
classement(resultats)qui prend cette liste et renvoie une nouvelle liste de tuples(rang, nom, performance)triée par performance croissante (le meilleur temps en premier). Utiliser un tri par insertion.Écrire une fonction
ecart_premier(resultats)qui renvoie un tuple(nom_dernier, ecart)contenant le nom du dernier classé et son écart en secondes avec le premier.Écrire une fonction
resume(resultats)qui affiche un tableau récapitulatif formaté avec le rang, le nom et le temps de chaque athlète, ainsi que l’écart avec le premier.
Correction
def classement(resultats):
"""Renvoie la liste triée par performance croissante avec le rang."""
# Copie pour ne pas modifier l'original
tri = list(resultats)
# Tri par insertion sur la performance (3e élément)
for i in range(1, len(tri)):
en_cours = tri[i]
j = i
while j > 0 and tri[j - 1][2] > en_cours[2]:
tri[j] = tri[j - 1]
j -= 1
tri[j] = en_cours
# Construction de la liste avec rang
return [(rang + 1, nom, perf) for rang, (nom, _, perf) in enumerate(tri)]
def ecart_premier(resultats):
"""Renvoie (nom_dernier, écart avec le premier)."""
cl = classement(resultats)
premier = cl[0]
dernier = cl[-1]
ecart = round(dernier[2] - premier[2], 1)
return (dernier[1], ecart)
def resume(resultats):
"""Affiche le tableau récapitulatif de la course."""
cl = classement(resultats)
meilleur_temps = cl[0][2]
print(f"{'Rang':<6} {'Nom':<10} {'Temps':>7} {'Écart':>7}")
print("-" * 32)
for rang, nom, perf in cl:
ecart = round(perf - meilleur_temps, 1)
ecart_str = f"+{ecart}s" if ecart > 0 else "—"
print(f"{rang:<6} {nom:<10} {perf:>6.1f}s {ecart_str:>7}")
courses = [
("Léa", "100m", 12.4),
("Karim", "100m", 11.8),
("Inès", "100m", 12.1),
("Théo", "100m", 11.5),
("Salma", "100m", 12.7),
]
resume(courses)
nom, ecart = ecart_premier(courses)
print(f"\nÉcart premier-dernier : {nom} à {ecart}s du premier")
Résultat :
Rang Nom Temps Écart
--------------------------------
1 Théo 11.5s —
2 Karim 11.8s +0.3s
3 Inès 12.1s +0.6s
4 Léa 12.4s +0.9s
5 Salma 12.7s +1.2s
Écart premier-dernier : Salma à 1.2s du premier
Points importants :
- Le déballage
rang, nom, perf = ...rend le code lisible dans la bouclefor. ecart_premierrenvoie un tuple qu’on déballe avecnom, ecart = ecart_premier(courses).resumeréutiliseclassement: c’est le principe de modularité.- Le tri par insertion modifie une copie de la liste (
list(resultats)) pour ne pas altérer les données d’origine.