Tuples et déballage
Une liste qui ne peut pas changer quand c'est exactement ce que vous voulez, le déballage pour utiliser des noms plutôt que des index, l'échange en une ligne, et le piège (5) contre (5,).
Comment voulez-vous apprendre ?
Le problème que nous résolvons
Trois jours de météo doivent être relevés — pour chaque jour, le nom, la température et l'humidité.
Une liste fait l'affaire : ["monday", 31.5, 78]. Cela fonctionne, mais deux choses vous tracassent.
D'abord, cette liste peut être modifiée. Si quelque chose fait un append sur l'enregistrement de lundi par erreur, Python ne motera pas — alors qu'un enregistrement n'est jamais censé contenir quatre choses. Mettre quelque chose qui ne doit pas changer dans un conteneur qui peut changer est un risque silencieux.
Ensuite, récupérer les trois valeurs oblige à écrire record[0], record[1], record[2] — par numéro, pas par nom. Six mois plus tard, personne qui lit record[1] ne saura si c'est la température ou l'humidité.
Un tuple répond aux deux : c'est une liste qui ne peut pas être modifiée — et il apporte une capacité appelée déballage, qui permet d'utiliser des noms plutôt que des index.
À la fin de ce chapitre, vous pourrez
- Construire un tuple, et dire quand un tuple convient et une liste non
- Placer plusieurs valeurs dans plusieurs noms d'un coup avec le déballage
- Échanger deux variables en une seule ligne
- Distinguer
(5)de(5,) - Expliquer pourquoi
appendsur un tuple lève uneAttributeError
Prérequis : Trier des listes, et les méthodes qui vont avec.
Un tuple — une liste qui ne peut pas changer
Des parenthèses rondes au lieu de carrées :
point = (3, 7)
print(point)
print(point[0])
print(len(point))(3, 7)
3
2Lecture, indexation, len, slice, in, parcours avec for — tout ce que vous faisiez sur une liste fonctionne. Il y a une différence, et c'est tout le sujet :
point = (3, 7)
point[0] = 5TypeError: 'tuple' object does not support item assignmentCe message vous dit quelque chose ? C'est mot pour mot ce que donnait le chapitre six lorsqu'un caractère à l'intérieur d'une chaîne était modifié, avec 'str' à la place de 'tuple'. Toutes les choses immuables de Python se plaignent dans la même langue.
Les méthodes qui modifient les choses sont aussi absentes :
point = (3, 7)
point.append(9)AttributeError: 'tuple' object has no attribute 'append'Une AttributeError signifie « cet objet n'a rien qui porte ce nom ». Un tuple ne peut pas être modifié, donc un tuple n'a tout simplement pas de méthode appelée append. Python s'arrête pendant la recherche de point.append, avant même d'essayer d'ajouter 9. Comparez avec l'exemple précédent : point[0] = 5 demandait une opération qu'un tuple n'autorise pas, donc c'était un TypeError ; ici, la méthode elle-même n'existe pas, donc c'est une AttributeError.
Pourquoi c'est un avantage, et non une limite
Au début, un tuple ressemble à une liste à laquelle on a retiré des fonctionnalités. Retournez le raisonnement : si quelque chose n'est pas censé changer, le mettre là où il ne peut pas changer arrête l'erreur avant qu'elle n'arrive.
Ajouter un troisième nombre à la coordonnée (3, 7) n'aurait aucun sens. Une date (2026, 9, 16) n'a pas de quatrième partie. Gardés dans des tuples, ces accidents arrivent tout de suite sous forme d'erreurs, au lieu d'arriver plus tard sous forme de bugs.
Règle : un nombre fixe de choses, chacune signifiant quelque chose de différent — tuple. Un nombre inconnu de choses, toutes de même nature — liste.
Trois jours de météo, ce sont donc des tuples dans une liste : le nombre de jours n'est pas connu (une liste), mais chaque enregistrement contient exactement trois choses (un tuple).
Le déballage — là où est le vrai bénéfice
point = (3, 7)
x, y = point
print(x)
print(y)3
7Deux noms et deux valeurs sur une seule ligne. Et maintenant c'est y plutôt que point[1] — un nom qui s'explique de lui-même quand on le lit.
Il faut autant de noms à gauche qu'il y a de valeurs à droite :
point = (3, 7)
x, y, z = pointValueError: not enough values to unpack (expected 3, got 2)Ce message est d'une aide inhabituelle — il indique à la fois combien de valeurs étaient attendues et combien sont arrivées.
Le déballage ne se limite pas aux tuples ; il fonctionne aussi sur les listes. Il est surtout utile avec les tuples, car c'est là que le nombre de valeurs est connu à l'avance.
Échanger, en une ligne
D'autres langages ont besoin d'une troisième variable temporaire pour échanger deux valeurs. Pas Python :
a = 1
b = 2
a, b = b, a
print(a, b)2 1Il vaut la peine de comprendre comment cette ligne fonctionne : Python évalue d'abord tout le côté droit, construit un tuple (2, 1), puis le déballe ensuite dans le côté gauche. Ainsi, bien que a change, l'ancienne valeur de b est déjà capturée, et rien n'est perdu.
Les parenthèses ne sont en fait pas nécessaires
point = 3, 7
print(point)
print(type(point))(3, 7)
<class 'tuple'>Ce qui fait un tuple, c'est la virgule, pas les parenthèses. Les parenthèses sont là pour la lisibilité. Une fois que vous savez cela, a, b = b, a n'a plus l'air magique — b, a à droite est tout simplement un tuple.
Et de là naît un piège :
one = (5)
really = (5,)
print(type(one))
print(type(really))
print(len(really))<class 'int'>
<class 'tuple'>
1(5) n'est pas un tuple — c'est un nombre entre parenthèses, exactement comme (2 + 3). Construire un tuple d'une seule valeur exige la virgule : (5,). Cela ressemble à une faute de frappe, et cette virgule fait toute la différence.
Des tuples dans une boucle
people = [("rafi", 22), ("ahmed", 35)]
for name, age in people:
print(f"{name} is {age}")rafi is 22
ahmed is 35for name, age in people déballe chaque tuple directement dans deux noms. Plus de person[0] ni de person[1] — et le code dit ce qu'il veut dire quand on le lit.
Vous l'avez déjà utilisé sans le savoir :
stock = ["pen", "bag"]
for pair in enumerate(stock):
print(pair)(0, 'pen')
(1, 'bag')enumerate renvoie des tuples. Écrire for position, item in enumerate(...) dans le chapitre douze, c'était les déballer — on n'avait juste pas de nom pour ça.
Convertir de l'un à l'autre
as_list = [3, 7]
as_tuple = (3, 7)
as_list.append(9)
print(as_list)
print(as_tuple)
print(list(as_tuple))
print(tuple(as_list))[3, 7, 9]
(3, 7)
[3, 7]
(3, 7, 9)list() et tuple() construisent l'un à partir de l'autre — une nouvelle chose à chaque fois, en laissant l'original tranquille. C'est ainsi qu'on « change » un tuple : on fabrique une liste, on la modifie, on en refait un tuple.
Un exemple complet
weather.py :
# A tuple is the right shape for a record that must not change
readings = [
("monday", 31.5, 78),
("tuesday", 33.0, 71),
("wednesday", 29.5, 85),
]
print("Day Temp Humidity")
for day, temp, humidity in readings:
print(f"{day:<10} {temp:>5} {humidity:>5}")
hottest = readings[0]
for reading in readings:
if reading[1] > hottest[1]:
hottest = reading
day, temp, humidity = hottest
print()
print(f"Hottest was {day} at {temp}")
temps = []
for _, temp, _ in readings:
temps.append(temp)
print("Temps :", temps)
print("Average :", round(sum(temps) / len(temps), 2))Day Temp Humidity
monday 31.5 78
tuesday 33.0 71
wednesday 29.5 85
Hottest was tuesday at 33.0
Temps : [31.5, 33.0, 29.5]
Average : 31.33Quatre choses à remarquer.
Une liste à l'extérieur, des tuples à l'intérieur. Le nombre de jours peut augmenter, donc l'objet extérieur est une liste. Chaque enregistrement contient exactement trois choses, donc les objets intérieurs sont des tuples. C'est la forme la plus courante dans les données réelles.
f"{day:<10}" et f"{temp:>5}" gardent les colonnes bien alignées. < aligne à gauche, > aligne à droite, et le nombre indique la largeur à occuper. Comme le :.2f du chapitre six, tout ce qui suit les deux-points est du formatage.
Trouver le jour le plus chaud a demandé reading[1], parce que pendant la comparaison, c'est le tuple entier qui est en main, et non un tuple déballé. Il est déballé dès qu'il est trouvé — c'est pourquoi la ligne suivante ne contient aucun index.
for _, temp, _ in readings — le tiret bas est une convention qui signifie « je n'ai pas besoin de celui-là ». Pour Python, c'est un nom ordinaire ; pour un lecteur, il dit quelles parties sont délibérément jetées.
En cas de problème
TypeError: 'tuple' object does not support item assignment Une tentative de modifier une valeur à l'intérieur d'un tuple. Les tuples ne peuvent pas être modifiés — utilisez une liste dès le départ, ou convertissez avec list(...), modifiez, puis reconvertissez.
AttributeError: 'tuple' object has no attribute 'append' La même cause sous d'autres habits. Aucune méthode de modification — append, remove, sort — n'existe sur un tuple. sorted(my_tuple) fonctionne, car elle renvoie une nouvelle liste et laisse le tuple tranquille.
ValueError: not enough values to unpack (expected 3, got 2) Il y a plus de noms à gauche que de valeurs à droite. print(len(record)) montre combien il y en a réellement dedans.
ValueError: too many values to unpack (expected 2) L'inverse — plus de valeurs que de noms.
J'ai fait un tuple d'une valeur et ce n'est pas un tuple La virgule manque. (5) est un nombre ; (5,) est un tuple.
Une liste à l'intérieur de mon tuple a changé Un tuple protège sa propre structure — ce qu'il contient ne peut pas changer. Mais si l'une de ces choses est elle-même modifiable, comme une liste, l'intérieur de cette liste peut encore changer. Dans ([1, 2], 3), vous pouvez faire un append sur la première liste.
Étape 4 sur 6 — Prédire
Vérifiez votre compréhension
Que s'affiche-t-il après le déballage ?
point = (3, 7)
x, y = point
print(y, x)- A3 7
- B(3, 7)
- CUne `ValueError`
- D7 3
Une tentative de faire un append sur un tuple. Quelle erreur arrive, et pourquoi celle-là ?
point = (3, 7)
point.append(9)- AUne `ValueError`
- BRien ne se passe ; le tuple est inchangé
- CUne `AttributeError` — un tuple ne peut pas changer, donc les méthodes de modification n'existent tout simplement pas dessus
- DUn `TypeError` — `append` n'est pas autorisé sur un tuple
Les deux lignes diffèrent d'une virgule. Que renvoie type() ?
one = (5)
really = (5,)
print(type(one))
print(type(really))- A<class 'int'> <class 'int'>
- B<class 'tuple'> <class 'tuple'>
- C<class 'int'> <class 'tuple'>
- D<class 'tuple'> <class 'int'>
Répondre nécessite un compte
Connectez-vous pour vérifier vos réponses
Les questions sont ci-dessus, et les résoudre de tête est ce qui compte vraiment. Connectez-vous pour voir les réponses, les explications et les indices à trois niveaux.
À vous de jouer
Écrivez un fichier appelé contacts.py contenant une liste d'au moins cinq personnes, chacune étant un tuple avec un nom, un âge et une matière préférée.
Ensuite :
- Affichez tout le monde en colonnes alignées, avec
for name, age, subject in contacts: - Trouvez la personne la plus âgée, déballez-la, et affichez une phrase à son sujet
- Construisez une liste avec seulement les noms, et affichez-la sur une ligne avec
join - Affichez l'âge moyen
- Échangez deux variables en une seule ligne et montrez que cela a fonctionné
Puis cassez-le trois fois exprès, et lisez chaque message :
- Essayez de modifier l'âge à l'intérieur de l'un des tuples
- Essayez de faire un
appendsur un tuple - Essayez de déballer un tuple de trois valeurs dans deux noms
Trois erreurs différentes reviendront — TypeError, AttributeError, ValueError. Savoir vous expliquer laquelle des trois c'est, et pourquoi, signifie que les tuples sont à vous.
Étape 6 sur 6
Défi — le quiz du chapitre
Dix questions, de la plus facile à la plus difficile. Les dernières sont difficiles exprès.
Connectez-vous pour faire le quiz