Listes, dictionnaires et tuples
Ce que ce chapitre apporte 5 points
- Ranger une suite de valeurs dans une liste, atteindre un élément par son indice, et la parcourir.
- Ajouter, retirer et modifier des éléments ; calculer une somme, un minimum, un maximum.
- Trier avec sorted() ou .sort(), en sachant lequel modifie la liste.
- Associer une valeur à une clé dans un dictionnaire, et le parcourir.
- Employer un tuple pour des valeurs qui vont ensemble et ne doivent plus bouger.
Une variable retient une valeur. Que fait-on quand on en a trente ?
Écrire note1, note2, note3 jusqu'à note30 est possible, et c'est une impasse : impossible d'en faire la moyenne sans écrire trente additions, impossible d'en ajouter une trente et unième sans modifier le programme. Il faut ranger plusieurs valeurs sous un seul nom. C'est l'objet de ce chapitre.
Il présente trois façons de le faire : la liste, qui range des valeurs dans l'ordre, le dictionnaire, qui les range par clé, et le tuple, qui ne se modifie plus. Il suffit pour cela des variables, des conditions et des boucles. Le reste, les tranches, les compréhensions, le texte vu comme une suite de caractères, les copies, les listes de listes et les ensembles, est rangé à part, en fin de chapitre.
La liste : une suite de valeurs
Une liste est une collection ordonnée et modifiable de valeurs, écrite entre crochets. Elle peut contenir des nombres, du texte, ou un mélange.
Quatre valeurs suffisent à voir l'intérêt : la moyenne s'écrit pareil pour quatre notes ou pour trois mille.
Atteindre un élément
Chaque élément a un indice, et les indices commencent à zéro.
0 est la source d'erreur numéro un sur les listes. Une liste de trois éléments a pour dernier indice 2, pas 3.La règle : le dernier indice vaut toujours
len(liste) - 1. Ou plus simplement, liste[-1], qui compte depuis la fin et ne se trompe jamais.
Le bloc suivant est faux exprès.
IndexError: list index out of range. Il y a bien trois notes, mais leurs indices sont 0, 1 et 2. Remplacer 3 par 2, ou mieux par -1, puis relancer.
Modifier
Une liste est mutable : on peut changer, ajouter, retirer après coup.
append, remove, pop et len suffisent pour presque tout. Il en existe d'autres, insert pour placer à un endroit précis, extend pour ajouter plusieurs éléments, clear pour vider : on les cherchera le jour où l'on en aura besoin.
Deux opérateurs déjà connus changent de sens sur des listes. + en colle deux bout à bout et * en répète une : [1, 2] + [3] donne [1, 2, 3], et [0] * 3 donne [0, 0, 0]. Ils n'additionnent ni ne multiplient rien, ils assemblent, et ils fabriquent une nouvelle liste sans toucher aux anciennes. La seconde écriture sert à préparer une liste de taille connue ; pour une grille, elle cache un piège, montré en fin de chapitre.
Parcourir et calculer
Trier
Trier se fait de deux façons, qui ne font pas la même chose. sorted(notes) fabrique une nouvelle liste triée et laisse l'original intact. notes.sort() trie la liste elle-même, sur place, et ne renvoie rien. Les deux acceptent reverse=True pour l'ordre décroissant.
Le bloc suivant est faux exprès.
None s'affiche, puis TypeError: 'NoneType' object is not subscriptable.
notes = notes.sort() jette la liste.sort() a bien trié la liste, puis a renvoyé None, la valeur qui signifie « rien ». En rangeant ce retour dans notes, on décolle l'étiquette de la liste triée pour la coller sur None : les données sont perdues.La règle :
notes.sort() seul sur sa ligne, ou triees = sorted(notes). Jamais les deux mélangés.Trier selon un autre critère que la valeur elle-même, des élèves par leur note par exemple, passe par un paramètre
key= qui attend une fonction : le chapitre sur bien écrire une fonction, dans sa section « Passer une fonction en paramètre », y revient.
1.Quel est le dernier indice valide d'une liste de 5 éléments ?
2.Après l = [3, 1, 2] puis l = l.sort(), que vaut l ?
Le dictionnaire : associer une clé à une valeur
Une liste de notes ne dit pas à qui appartient chaque note. On serait tenté de tenir deux listes en parallèle, prenoms et notes, et de les faire correspondre par leur indice. C'est fragile : il suffit d'en trier une pour tout casser.
Un dictionnaire associe des clés à des valeurs, entre accolades, avec la syntaxe cle: valeur. On accède à une valeur par sa clé, jamais par un indice.
Liste ou dictionnaire : la question à se poser.
Comment vais-je retrouver une valeur ?
Par sa position, ou parce que je veux toutes les parcourir dans l'ordre : c'est une liste.
Par un identifiant, un nom, un code, une date : c'est un dictionnaire.
Le symptôme qui doit alerter : deux listes de même longueur qu'on parcourt avec le même indice. Cela veut presque toujours dire qu'un dictionnaire s'imposait.
Parcourir un dictionnaire
.keys() donne les clés, .values() les valeurs, .items() les paires. C'est .items() qu'on emploiera le plus.
La clé qui n'existe pas
KeyError: 'Zoe'. Demander une clé absente arrête le programme. Quand on n'est pas sûr, .get() répond sans planter, et accepte une valeur de repli.
notes.get("Zoe") renvoie None, qui signifie « rien », et non 0, qui est une note. Calculer avec None déclenche un TypeError.Quand la valeur sert à un calcul, toujours donner un repli :
notes.get("Zoe", 0). Quand la question est seulement de savoir si la clé existe, in est plus clair qu'une comparaison à None.
Compter des occurrences
Compter les occurrences est l'exercice type du dictionnaire, et celui où l'on se perd le plus vite : la clé change à chaque tour, et la valeur associée aussi. La trace le déroule sur un mot, qu'une boucle for parcourt lettre par lettre comme une liste.
| 1 | compte = {} |
| 2 | for c in "abraca": |
| 3 | if c in compte: |
| 4 | compte[c] = compte[c] + 1 |
| 5 | else: |
| 6 | compte[c] = 1 |
| 7 | print(compte) |
Variables
| compte | {} |
Le if c in compte distingue les deux seuls cas possibles : la lettre a déjà été vue, et il faut incrémenter ; ou c'est la première fois, et il faut créer l'entrée à 1. Oublier le else donne une erreur de clé absente au tout premier caractère, ce que la trace montre en s'arrêtant net.
1.Que renvoie {"x": 1}.get("y") ?
2.Deux listes prenoms et notes de même longueur, parcourues avec le même indice. Que faudrait-il ?
Le tuple : des valeurs qui vont ensemble
Un tuple s'écrit entre parenthèses et ne se modifie plus après sa création. Ce n'est pas une liste au rabais : c'est une garantie.
Le bloc suivant est faux exprès : il tente de modifier un tuple.
TypeError: 'tuple' object does not support item assignment. Le refus est le point : un tuple sert quand les valeurs vont ensemble et ne doivent pas bouger séparément. Une coordonnée, une couleur, une date, un couple largeur-hauteur.
Le dépaquetage est ce qu'on en fait le plus : x, y = point range chaque valeur sous son nom, et la même écriture échange deux variables sans variable temporaire.
Une fonction qui renvoie plusieurs valeurs d'un coup, return mini, maxi, renvoie en fait un tuple, que l'appel dépaquette : le chapitre sur les fonctions le montre dans sa partie « Pour aller plus loin ».
Quelle structure choisir
| Structure | Écriture | Modifiable | Quand l'employer |
|---|---|---|---|
| Liste | [1, 2, 3] | oui | une suite de valeurs, parcourue ou indexée |
| Dictionnaire | {"a": 1} | oui | retrouver une valeur par un identifiant |
| Tuple | (3, 7) | non | des valeurs fixes qui vont ensemble |
Deux autres structures complètent ce tableau en fin de chapitre : la chaîne, du texte qui ne se modifie pas, et l'ensemble, des valeurs distinctes sans ordre.
Pour aller plus loin
Rien de ce qui suit n'est nécessaire pour ranger ses premières données. Ce sont des écritures plus courtes et des pièges qu'on rencontre ensuite, une fois la liste et le dictionnaire bien en main.
La liste est l'équivalent Python du tableau, dont le chapitre d'algorithmique sur les tableaux et leur parcours traite indépendamment du langage. Deux différences comptent, et elles se paient : les indices commencent ici à 0 et non à 1, et une liste Python s'allonge toute seule là où un tableau a une taille fixée.
Découper une tranche
Deux indices séparés par un deux-points prennent un morceau de la liste. La borne de gauche est incluse, celle de droite exclue, exactement comme dans range.
L'exclusion de la borne droite paraît arbitraire, et elle a une bonne raison : elle rend les tranches raboutables. notes[:3] et notes[3:] reconstituent exactement la liste, sans doublon ni oubli, et la longueur d'une tranche [a:b] vaut simplement b - a.
notes[:] est une autre façon d'écrire notes.copy() : découper une liste fabrique une nouvelle liste, et la modifier ne touche pas l'original. Le chapitre sur NumPy montrera que ce n'est pas vrai de tous les objets découpables, et c'est l'une des rares fois où Python change de règle.
Construire une liste en une ligne : la compréhension
Filtrer une liste pour en garder une partie revient si souvent que Python lui donne une écriture dédiée, la compréhension : [n for n in notes if n >= 10]. Elle se lit comme la boucle, dans le même ordre : « les n, pour chaque n de notes, si n >= 10 ». Les quatre lignes du schéma « Compter, cumuler, filtrer », liste vide, for, if, append, tiennent entre deux crochets.
La partie if est facultative. Sans elle, la compréhension transforme chaque élément : [n * 2 for n in notes] double toutes les valeurs. Avec des accolades et un deux-points, elle fabrique un dictionnaire, ici des longueurs de pièces converties de millimètres en mètres.
Les deux dernières lignes reprennent le compteur et l'accumulateur. Placée directement dans sum(...), sans crochets, la même écriture fournit les valeurs une à une à sum, sans construire de liste intermédiaire : sum(1 for ...) ajoute 1 pour chaque élément retenu, donc les compte, et sum(n for ...) les additionne.
elif, un affichage ou plusieurs résultats à la fois, la boucle écrite en entier redevient la bonne forme.Le test est simple : si l'on doit relire la ligne deux fois pour savoir ce qu'elle fait, c'est une boucle qu'il fallait.
Le texte, une suite de caractères
Une chaîne se comporte presque comme une liste de lettres, à une différence près : elle est immuable. On peut la lire et en fabriquer de nouvelles, jamais changer une lettre en place.
Les deux méthodes qui servent le plus font le lien avec les listes : split() découpe un texte en liste, join() recolle une liste en texte.
mot.upper() ne change pas mot : il renvoie une nouvelle chaîne. Si on veut garder le résultat, il faut le ranger : mot = mot.upper().C'est l'inverse des listes, où
notes.append(15) modifie la liste elle-même et ne renvoie rien. Cette différence explique la moitié des surprises du chapitre.
Pour chercher dans un texte, in fonctionne comme sur une liste, mais il cherche un morceau de texte : "OK" in ligne. Quelques méthodes complètent ce test : startswith et endswith regardent le début et la fin, find donne la position d'un morceau (ou -1 s'il n'y est pas), count compte ses apparitions, strip retire les espaces et le saut de ligne aux deux bouts, et isdigit dit si le texte n'est fait que de chiffres. Elles servent toutes à nettoyer une ligne de relevé avant de s'en servir.
1.Que vaut [x * 2 for x in [1, 5, 8] if x > 3] ?
2.Que fait mot.upper() sur mot = "python" ?
Deux étiquettes, une seule liste
Rappel du chapitre 2 : une variable est une étiquette collée sur une valeur. Avec les listes, cette image cesse d'être une commodité et devient indispensable.
equipe_b = equipe_a ne fabrique pas une deuxième liste : elle colle une deuxième étiquette sur la liste existante. Modifier la liste par l'une ou par l'autre revient au même, puisqu'il n'y en a qu'une.Pour obtenir une copie indépendante :
equipe_b = equipe_a.copy(). Elle suffit tant que la liste contient des nombres ou du texte ; pour une liste de listes, il faudra davantage, comme on le verra plus bas.Ce comportement ne vaut que pour les valeurs modifiables, listes et dictionnaires. Avec un nombre ou un texte, la question ne se pose pas : on ne peut pas les modifier, donc on ne peut pas surprendre l'autre étiquette.
Le dessin ci-dessous montre la situation telle qu'elle est en mémoire, et non telle qu'on l'imagine. Il n'y a qu'une seule liste, et deux étiquettes pointées dessus.
L'image de la boîte, qui suffit tant qu'on manipule des nombres, cesse ici de fonctionner. Une variable n'est pas une boîte qui contient une valeur : c'est une étiquette collée sur un objet. Deux étiquettes sur le même objet, c'est une situation ordinaire, et la seule façon de la comprendre est de la voir.
Les listes de listes
Un tableau de relevés, une ligne par jour et une colonne par capteur, se range dans une liste de listes : chaque élément de la liste extérieure est lui-même une liste, une ligne du tableau. releves[1] donne la deuxième ligne, et releves[1][2] l'élément de rang 2 de cette ligne : on lit d'abord la ligne, puis la colonne.
Le parcours complet est exactement les boucles imbriquées du chapitre précédent : la boucle extérieure choisit la ligne, l'intérieure en parcourt toutes les colonnes avant de passer à la suivante.
[[0] * 3] * 3 ne fabrique qu'une seule ligne[[0] * 3] * 3 est tentante. Elle fabrique une ligne de trois zéros, puis une liste qui porte trois étiquettes vers cette même ligne. Modifier une case modifie donc toute la colonne.La forme correcte est une compréhension, qui fabrique une ligne neuve à chaque tour :
[[0] * 3 for _ in range(3)]. Le nom _ est une variable comme une autre, qu'on emploie par convention quand sa valeur ne sert pas.
Le même mécanisme rattrape .copy(). Elle fabrique une nouvelle liste extérieure, mais y range les mêmes lignes que l'original : c'est une copie superficielle, qui ne descend pas d'un niveau. Pour une liste de listes, ou une liste de dictionnaires, il faut une copie profonde, que fournit copy.deepcopy. La ligne import copy va chercher cet outil dans la bibliothèque livrée avec Python ; le chapitre sur la modularité explique ce mécanisme.
Dans la première grille, les trois lignes ont reçu le 1 ; dans la seconde, une seule. Et la copie par .copy() a vu apparaître "A3", parce que sa première ligne est celle de l'original, alors que la copie profonde n'a pas bougé.
1.Après a = [1, 2], b = a, b.append(3), que vaut a ?
2.Après g = [[0] * 2] * 2 puis g[0][0] = 5, que vaut g ?
3.Pour dupliquer une liste de listes qu'on va modifier, que faut-il ?
Un tuple comme clé de dictionnaire
Une clé de dictionnaire doit être immuable : un tuple convient, une liste non. C'est ce qui permet de repérer une case d'une grille par ses deux coordonnées.
L'ensemble : des valeurs sans doublon
Un ensemble retient des valeurs sans doublon et sans ordre. Il répond à deux questions que les autres structures traitent mal : « quelles sont les valeurs distinctes ? » et « celle-ci est-elle dedans ? ».
La conversion en ensemble puis retour en liste est la façon d'enlever les doublons en Python. Elle tient en une expression, list(set(valeurs)), au prix de l'ordre, que sorted rétablit si besoin.
Les opérations ensemblistes se lisent comme en mathématiques :
Pourquoi le test d'appartenance y est si rapide. Chercher une valeur dans une liste de cent mille éléments oblige à les parcourir jusqu'à la trouver. Dans un ensemble, la réponse arrive en un temps qui ne dépend pas de la taille, parce que la valeur elle-même indique où regarder.
D'où la règle : dès qu'un programme fait beaucoup de if x in collection sur une grande collection dont l'ordre est indifférent, l'ensemble est le bon choix. C'est le même mécanisme que la clé de dictionnaire, et c'est pourquoi un ensemble n'accepte lui aussi que des valeurs immuables.
1.Pourquoi un tuple peut-il servir de clé de dictionnaire, et pas une liste ?
2.set([3, 1, 3, 2, 1]) donne quoi ?
Mettre en pratique
Le bulletin. À partir du dictionnaire ci-dessous, afficher la moyenne générale avec deux décimales, puis le nom du meilleur élève.
Afficher la solution
La moyenne se lit directement sur les valeurs : sum(notes.values()).
Pour le maximum, on emploie le schéma « préparer, parcourir, comparer » : une variable qui retient le meilleur trouvé jusqu'ici, initialisée à une valeur que tout dépassera. Python offre un raccourci, max(notes, key=notes.get), mais la boucle explicite est ce qu'on attend de soi en devoir, et c'est elle qui se transpose à tous les autres problèmes.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Indices, parcours, ajout et suppression.
- Le troisième capteur du bus1 · Débuter
- Les relevés hors tolérance2 · Fonctions
- Débogage : le classement a disparu2 · Fonctions
- Débogage : un négatif survit au nettoyage4 · Avancé
- Parcourir une série de relevés1 · Débuter
- Des mesures brutes aux volts2 · Fonctions
- Les derniers relevés du tableau de bord3 · Confirmé
- Défi : la moyenne glissante4 · Avancé
Découper, assembler et transformer du texte.
- Lire une chaîne1 · Débuter
- Débogage : l'alarme qui passe inaperçue2 · Fonctions
- Une jauge de batterie2 · Fonctions
- Un code d'activation saisi à la main2 · Fonctions
- Découper une trame2 · Fonctions
- Un nom de fichier pour chaque abri2 · Fonctions
- Des décimales à la française3 · Confirmé
- Les fichiers que le serveur accepte3 · Confirmé
Associer des clés à des valeurs et les parcourir.
- Lire un dictionnaire1 · Débuter
- Débogage : KeyError au premier badge3 · Confirmé
- Un seuil par type de capteur2 · Fonctions
- Le coût des pièces d'une intervention2 · Fonctions
- Zéro en stock n'est pas inconnu2 · Fonctions
- Les références à recommander3 · Confirmé
- Deux capteurs à la même adresse3 · Confirmé
- Défi : l'heure la plus chargée4 · Avancé
Listes de listes, grilles et matrices.
- Lire une matrice1 · Débuter
- Débogage : une intervention cochée pour tous3 · Confirmé
- Débogage : la colonne lue de travers4 · Avancé
- Les capteurs muets2 · Fonctions
- Le total de chaque machine3 · Confirmé
- Les capteurs par emplacement3 · Confirmé
- Le stock par rayon3 · Confirmé
- Défi : le capteur le plus instable4 · Avancé