NSI · Première
Types construits : tuples, listes et dictionnaires
Tuples, listes, matrices et dictionnaires organisent plusieurs valeurs. Apprends à les lire, les parcourir et les modifier, puis à repérer les copies qui partagent encore des données avec l'original.
Explications et exemples en accès libre. Ateliers, quiz et cartes avec l’abonnement.
Prévoir mon tempsExplications et exemples en accès libre
Une première étude des explications, schémas, exemples résolus et erreurs expliquées. Les activités, productions, quiz et cartes réservés à l’abonnement ne sont pas comptés ici.
- Comprendre1363 mots d’explication et 4 schémas
- 10 à 17 min
- Étudier les exemples et les erreurs18 cas, exemples et activités guidés
- 36 à 66 min
Étude du cours en accès libre, environ45 min à 1 h 25
Voir le calcul et le temps par étape
Le calcul suit automatiquement les explications et les tâches présentes dans le cours. Ses coefficients sont des repères de planification, pas des temps mesurés auprès d’élèves.
- Lecture active : 1363 mots, à raison de 160 à 220 mots par minute.
- Schémas : 4, avec 1 à 2 min pour lire chacun.
- Exemple guidé : 6 × 2 à 4 min.
- Suivre le code résolu et ses tests : 6 × 3 à 5 min.
- Comprendre une erreur expliquée : 6 × 1 à 2 min.
- P-uplet : rendre plusieurs valeurs sous un contrat unique7 à 15 min
- Liste : modifier par indice ou construire une nouvelle valeur ?6 à 13 min
- Compréhensions et matrices : construire sans partager les lignes7 à 15 min
- Alias et copie : deux noms désignent-ils le même objet ?7 à 14 min
- Enregistrement : nommer les champs plutôt que mémoriser des positions6 à 12 min
- Dictionnaire : rechercher par clé et compter sans erreur d'initialisation8 à 15 min
Les sous-totaux sont arrondis à la minute, puis additionnés. La fourchette totale est élargie aux cinq minutes voisines. Les étapes ci-dessus comprennent leurs explications et exemples ; elles ne s’ajoutent pas une seconde fois au total.
Adapte ce repère à tes acquis et au soin apporté aux exercices. Les pauses, les reprises, la consultation des sources externes et les révisions suivantes s’ajoutent selon tes besoins.
Avec les ateliers, le projet, le quiz et les cartes : environ 2 h 40 à 4 h 40, à répartir sur plusieurs séances.
Objectifs du cours
Ce que tu vas savoir faire
- Choisir p-uplet, liste, enregistrement ou dictionnaire à partir des opérations et invariants attendus.
- Écrire une fonction qui renvoie plusieurs valeurs et décomposer son résultat sans ambiguïté.
- Lire, modifier et parcourir une liste en distinguant élément, indice et nouvelle liste.
- Construire des listes par compréhension et des matrices rectangulaires sans partage accidentel de lignes.
- Expliquer mutabilité, identité, alias, copie superficielle et copie imbriquée à partir d'une trace.
- Construire et parcourir un dictionnaire par clés, valeurs et couples, en traitant explicitement les clés absentes.
Étape du cours · 7 à 15 min
P-uplet : rendre plusieurs valeurs sous un contrat unique
Un p-uplet est une suite ordonnée dont les positions ne peuvent pas être réaffectées. Il convient lorsque plusieurs résultats forment un tout, par exemple minimum, maximum et moyenne d'une même série. La fonction renvoie un seul objet composé ; l'appelant peut le conserver, accéder par indice ou le décomposer. Le contrat doit documenter l'ordre, car (minimum, maximum) et (maximum, minimum) ont le même type Python mais pas le même sens.
On écrit par exemple t = (2, 8, 4.0) : len(t) vaut 3 et t[0] vaut 2. () est vide ; (7,) contient un élément, tandis que (7) est simplement le nombre 7. C'est la virgule qui distingue ce singleton. minimum, maximum, moyenne = t associe les trois valeurs aux trois noms ; leur nombre doit correspondre.
L'immutabilité porte sur les positions du p-uplet, pas nécessairement sur tout objet qu'il contient. Après t = ([1], 2) puis t[0].append(3), t vaut ([1, 3], 2) : sa première position désigne toujours la même liste, qui a changé. Dans notre résumé d'une série de nombres, seuls des nombres sont renvoyés. La liste vide est refusée, car minimum et moyenne n'y sont pas définis.
Voir pour comprendre
Un résultat composé, des positions à nommer
Pour les valeurs [4, 1, 9, 2], la fonction resume renvoie (1, 9, 4.0).
| Position | Rôle | Valeur |
|---|---|---|
| 0 | minimum | 1 |
| 1 | maximum | 9 |
| 2 | moyenne | 16 ÷ 4 = 4.0 |
Lis le schéma. Cache la colonne des valeurs et reconstruis le résultat. Explique pourquoi (9, 1, 4.0) ne respecterait pas le même contrat.
Le type tuple ne garantit pas l'ordre sémantique de ses éléments. Cet ordre appartient au contrat de la fonction.
Exemples résolus et erreurs expliquées
Renvoyer trois résultats, puis les décomposer
- Pour [8, 2, 2], le minimum est 2 et le maximum est 8. Le total vaut 12, donc la moyenne vaut 12 / 3 = 4.0.
- La fonction renvoie (2, 8, 4.0), dans l'ordre annoncé : minimum, maximum, moyenne. Ce p-uplet est un seul objet à trois positions.
- Après minimum, maximum, moyenne = resume([8, 2, 2]), les trois noms valent respectivement 2, 8 et 4.0. Le maximum est aussi accessible par resultat[1] si l'on a écrit resultat = resume([8, 2, 2]).
- La liste d'entrée reste [8, 2, 2]. Vérifier le résultat ne suffit pas : on vérifie aussi que la fonction n'a pas trié ni modifié cette liste.
Conclusion. Choisis et annonce l'ordre du résultat. La décomposition nomme les positions, elle ne devine pas leur sens.
Laboratoire de code
Languepython
Butcalculer en un parcours un résultat composé et documenter l'ordre du p-uplet
Code solution
def resume(valeurs):
if len(valeurs) == 0:
raise ValueError("série vide")
minimum = valeurs[0]
maximum = valeurs[0]
total = 0
for valeur in valeurs:
if valeur < minimum:
minimum = valeur
if valeur > maximum:
maximum = valeur
total += valeur
return minimum, maximum, total / len(valeurs)Tests
assert resume([7]) == (7, 7, 7.0)
assert resume([4, 1, 9, 2]) == (1, 9, 4.0)
assert resume([-3, -7, -1]) == (-7, -1, -11 / 3)
minimum, maximum, moyenne = resume([10, 0, 5])
assert (minimum, maximum, moyenne) == (0, 10, 5.0)Trace
- initialement minimum=maximum=4 et total=0 pour [4,1,9,2]
- après 1, minimum=1, maximum=4, total=5 ; après 9, maximum=9
- après 2, total=16 et len=4 ; le p-uplet renvoyé est (1,9,4.0)
Clinique de bogue
Indice observéla fonction renvoie les bonnes bornes mais modifie silencieusement l'ordre de la liste fournie par l'appelant
CauseLa méthode sort agit sur l'objet mutable reçu. Le contrat ne promettait pas cette mutation et un alias détenu par l'appelant observe le nouvel ordre, ce qui peut casser une étape ultérieure.
Étape du cours · 6 à 13 min
Liste : modifier par indice ou construire une nouvelle valeur ?
Une liste se crée avec des crochets : valeurs = [6, -2, 4], ou [] si elle est vide. Ses indices non négatifs vont de 0 à len(valeurs)-1 : ici 0, 1 et 2. valeurs[1] vaut −2 et valeurs[3] provoque IndexError. Python accepte aussi des indices négatifs, comme −1 pour le dernier élément ; dans nos parcours, nous utilisons les indices de 0 à la longueur moins un.
for valeur in valeurs parcourt les éléments ; for i in range(len(valeurs)) parcourt leurs indices. enumerate(valeurs) fournit à la fois indice et valeur. Affecter valeur = 0 ne change que le nom local ; affecter valeurs[i] = 0 remplace une case. append ajoute un élément à la fin et len donne la longueur. Nos tableaux contiennent des nombres de même type, conformément au modèle étudié en Première.
Une fonction choisit entre modifier l'entrée et construire une nouvelle liste. Ici, sans_negatifs remplace chaque négatif par zéro dans une nouvelle liste : elle ne supprime aucun élément et conserve la longueur. Un filtre, lui, pourrait supprimer les négatifs. Les tests distinguent liste vide, zéro, valeurs déjà positives et plusieurs négatifs consécutifs.
Exemples résolus et erreurs expliquées
Changer une case ou changer seulement un nom ?
- Partons de valeurs = [6, -2, 4]. À l'indice 1, la valeur est −2. Les indices 0, 1, 2 décrivent les positions, pas les nombres stockés.
- Dans for valeur in valeurs, écrire valeur = 0 pour une valeur négative laisse la liste [6, -2, 4] inchangée : seul le nom valeur est réaffecté.
- Écrire valeurs[1] = 0 modifie au contraire la case : la liste devient [6, 0, 4]. Un autre nom désignant cette liste observe aussi la modification.
- Pour préserver l'entrée, sans_negatifs([6, -2, 4]) construit [6, 0, 4] séparément. Filtrer avec [x for x in valeurs if x >= 0], sur l'entrée initiale, donnerait [6, 4] : ce n'est pas le même travail.
Conclusion. Avant de coder, annonce si tu remplaces, si tu filtres, et si tu modifies l'entrée. Ces trois questions déterminent les tests.
Laboratoire de code
Languepython
Buttransformer une liste sans modifier l'objet d'entrée et tracer les indices visités
Code solution
def sans_negatifs(valeurs):
resultat = []
for valeur in valeurs:
if valeur < 0:
resultat.append(0)
else:
resultat.append(valeur)
return resultat
def positions_de(valeurs, cible):
positions = []
for indice, valeur in enumerate(valeurs):
if valeur == cible:
positions.append(indice)
return positionsTests
source = [3, -2, -1, 0, 5]
assert sans_negatifs(source) == [3, 0, 0, 0, 5]
assert source == [3, -2, -1, 0, 5]
assert sans_negatifs([]) == []
assert positions_de([4, 2, 4, 4], 4) == [0, 2, 3]
assert positions_de([1, 2], 7) == []Trace
- résultat commence vide, source reste [3,-2,-1,0,5]
- 3 est ajouté ; -2 puis -1 satisfont valeur<0 et ajoutent chacun 0
- 0 n'est pas négatif et reste 0 ; 5 est ajouté ; source et résultat sont deux objets distincts
Clinique de bogue
Indice observéannule_negatifs([2,-3]) renvoie encore [2,-3]
CauseLe nom valeur reçoit successivement les éléments, mais l'affectation valeur = 0 ne réaffecte aucune case de la liste. Pour muter, il faut écrire explicitement valeurs[indice].
Étape du cours · 7 à 15 min
Compréhensions et matrices : construire sans partager les lignes
Une compréhension [expression for element in source if condition] construit une nouvelle liste en rendant visibles transformation et filtre. Elle convient aux règles simples ; une boucle explicite reste préférable lorsque plusieurs états ou contrôles doivent être expliqués. Pour une matrice rectangulaire, a[i][j] désigne la colonne j de la ligne i et les limites dépendent de deux dimensions distinctes.
La construction [[0] * colonnes] * lignes ne fabrique qu'une seule liste interne puis répète sa référence. Modifier une cellule modifie alors la même colonne de chaque ligne. Une compréhension externe exécute la création de ligne à chaque tour et produit des objets distincts. La transposition exige en plus de vérifier que toutes les lignes ont la même longueur, faute de quoi la notion de colonne complète n'est pas définie.
Les dimensions et la borne n de carres_pairs sont des entiers non négatifs, sans booléens. Les assertions rendent ce contrat visible pendant l'étude ; elles ne remplacent pas la validation d'entrées d'un service. Notre représentation renvoie [] pour une matrice sans ligne ou sans colonne. Dans ce dernier cas, elle perd l'information sur le nombre de lignes initial : transposer deux fois [[], []] ne reconstitue donc pas [[], []].
Voir pour comprendre
Transposer : les colonnes deviennent des lignes
a = [[1, 2, 3], [4, 5, 6]] possède 2 lignes et 3 colonnes. Sa transposée t possède 3 lignes et 2 colonnes.
| Colonne de a | Valeurs lues | Ligne de t |
|---|---|---|
| 0 | 1 puis 4 | [1, 4] |
| 1 | 2 puis 5 | [2, 5] |
| 2 | 3 puis 6 | [3, 6] |
Lis le schéma. Suis le nombre 6 : dans a, il est à la ligne 1 et à la colonne 2. Où se trouve-t-il dans t ?
Le nombre 6 passe de la case a[1][2] à t[2][1]. Les deux indices sont échangés : une matrice 2 × 3 devient une matrice 3 × 2.
Exemples résolus et erreurs expliquées
Lire une compréhension dans l'ordre du calcul
- Dans [x * x for x in range(7) if x % 2 == 0], le parcours fournit d'abord les nombres 0 à 6. La borne 7 n'est pas incluse.
- Le filtre x % 2 == 0 garde 0, 2, 4 et 6. Pour chaque nombre gardé, l'expression x * x produit son carré : [0, 4, 16, 36].
- Pour a = [[1, 2, 3], [4, 5, 6]], a[1][2] vaut 6 : ligne 1, colonne 2. La matrice possède deux lignes de trois éléments.
- Transposer consiste à transformer chaque colonne en ligne. La colonne 0 donne [1, 4], la colonne 1 [2, 5], et la colonne 2 [3, 6]. Le résultat a trois lignes de deux éléments.
Conclusion. Lis une compréhension en trois temps : parcourir, filtrer, produire. Pour une transposition, suis une cellule de a[i][j] vers t[j][i].
Laboratoire de code
Languepython
Butconstruire une matrice sans alias et écrire sa transposée avec dimensions vérifiées
Code solution
def matrice_nulle(lignes, colonnes):
assert type(lignes) is int and type(colonnes) is int
assert lignes >= 0 and colonnes >= 0
return [[0 for _ in range(colonnes)] for _ in range(lignes)]
def transposee(matrice):
if not matrice:
return []
colonnes = len(matrice[0])
if any(len(ligne) != colonnes for ligne in matrice):
raise ValueError("matrice non rectangulaire")
return [[matrice[i][j] for i in range(len(matrice))] for j in range(colonnes)]
def carres_pairs(n):
assert type(n) is int and n >= 0
return [x * x for x in range(n) if x % 2 == 0]Tests
m = matrice_nulle(2, 3)
m[0][1] = 7
assert m == [[0, 7, 0], [0, 0, 0]]
assert transposee([[1, 2, 3], [4, 5, 6]]) == [[1, 4], [2, 5], [3, 6]]
assert transposee([]) == []
assert transposee([[], []]) == []
assert transposee([[5]]) == [[5]]
assert carres_pairs(7) == [0, 4, 16, 36]Trace
- la compréhension externe crée la ligne 0 puis une nouvelle ligne 1
- après m[0][1]=7, seule la case 1 de la ligne 0 change ; la ligne elle-même reste le même objet
- pour la transposée 2×3, chaque nouvelle ligne j collecte matrice[0][j] puis matrice[1][j], donnant une matrice 3×2
Clinique de bogue
Indice observéaprès m = matrice_nulle(3) puis m[0][0] = 1, les trois lignes commencent par 1
CauseLa multiplication répète trois références vers la même sous-liste au lieu de construire trois lignes. Le contenu affiché initialement masque l'identité partagée jusqu'à la première mutation.
Étape du cours · 7 à 14 min
Alias et copie : deux noms désignent-ils le même objet ?
Après b = a, les noms a et b désignent le même objet liste. b.append(...) est donc visible via a. Une comparaison a == b porte sur les contenus, tandis que a is b porte sur l'identité. Une affectation ne copie pas automatiquement un objet. Avec des nombres immuables, réaffecter un nom, par exemple x = x + 1, ne modifie pas le nombre auquel un autre nom reste associé.
liste.copy() ou list(liste) crée une nouvelle liste externe, mais conserve les références vers ses éléments : c'est une copie superficielle. Notre fonction copie ensuite chaque ligne d'une grille de nombres avant de remplacer une case. Les listes externes et les lignes sont distinctes. Si les cases contenaient elles-mêmes des listes, celles-ci resteraient partagées : une copie ligne par ligne n'est pas une copie à toute profondeur.
Voir pour comprendre
Copier une grille : à quel niveau partage-t-on ?
Compare ces trois constructions à partir d'une grille de nombres.
| Écriture | Liste externe | Lignes internes |
|---|---|---|
b = a | même objet | mêmes objets |
b = a.copy() | nouvel objet | mêmes objets |
b = [ligne.copy() for ligne in a] | nouvel objet | nouveaux objets |
Lis le schéma. Suis d'abord la liste externe puis une ligne. Quelle construction empêche b[0][0] de modifier a[0][0] ?
Copier le conteneur externe ne copie pas ses éléments. La copie ligne par ligne suffit ici pour une grille de nombres, pas pour toute imbrication arbitraire.
Exemples résolus et erreurs expliquées
Suivre une mutation à deux niveaux
- Partons de a = [[1, 2], [3, 4]], puis b = a.copy(). Le test b is a est faux, mais b[0] is a[0] est vrai : seule la liste externe a été copiée.
- Après b[0][1] = 9, a vaut aussi [[1, 9], [3, 4]]. L'affectation atteint la ligne commune aux deux conteneurs.
- Repartons de a = [[1, 2], [3, 4]] et créons c = [ligne.copy() for ligne in a]. Après c[0][1] = 9, a reste [[1, 2], [3, 4]].
- Il faut comparer toutes les lignes pour détecter tout partage : d = [a[1], a[0]] partage les deux lignes avec a, mais à des positions inversées. Comparer seulement les mêmes indices ne le détecterait pas.
Conclusion. Le contenu répond à « quelles valeurs ? » ; l'identité répond à « quels objets partagés ? ». Pour une grille de nombres, copier chaque ligne sépare les cellules modifiables.
Laboratoire de code
Languepython
Butproduire une grille modifiée sans partager ses lignes avec la source
Code solution
def avec_cellule(grille, i, j, valeur):
assert type(i) is int and type(j) is int
if not (0 <= i < len(grille)):
raise IndexError("ligne hors limites")
if not (0 <= j < len(grille[i])):
raise IndexError("colonne hors limites")
copie = [ligne.copy() for ligne in grille]
copie[i][j] = valeur
return copie
def partage_ligne(a, b):
return any(ligne_a is ligne_b for ligne_a in a for ligne_b in b)Tests
source = [[1, 2], [3, 4]]
resultat = avec_cellule(source, 1, 0, 9)
assert resultat == [[1, 2], [9, 4]]
assert source == [[1, 2], [3, 4]]
assert not partage_ligne(source, resultat)
assert partage_ligne(source, [source[1], source[0]])
assert partage_ligne(source, [source[1]])
assert not partage_ligne(source, [])
resultat[0][0] = 8
assert source[0][0] == 1Trace
- source contient deux références de lignes ; copie crée une nouvelle liste pour chacune
- copie[1][0]=9 modifie seulement la seconde nouvelle ligne
- aucune ligne de source n'est une ligne de copie ; partage_ligne compare toutes les paires, même à des indices différents
Clinique de bogue
Indice observéla liste externe est différente, mais modifier copie[0][0] change aussi grille[0][0]
CauseLa copie superficielle duplique seulement le conteneur externe. Ses éléments sont encore les mêmes objets lignes ; l'affectation de cellule traverse donc une référence partagée.
Étape du cours · 6 à 12 min
Enregistrement : nommer les champs plutôt que mémoriser des positions
Un enregistrement rassemble des valeurs de types éventuellement différents sous des champs nommés. Pour un livre fictif, code, titre et pages expriment mieux le sens que les positions 0, 1 et 2 d'une liste. Le nom de champ réduit les inversions et permet de contrôler séparément chaque domaine. Un dictionnaire Python fournit ici une implémentation simple de p-uplet nommé au sens du programme.
Un champ nommé ne garantit pas à lui seul la cohérence. Le constructeur vérifie un code et un titre textuels non vides ainsi qu'un nombre de pages entier strictement positif. Il renvoie un nouveau dictionnaire contenant ces trois valeurs immuables. En Python, type(pages) is int écarte les booléens : True n'est pas un nombre de pages acceptable. Les fonctions description et total_pages attendent des livres respectant ce schéma.
Exemples résolus et erreurs expliquées
Lire un livre par ses champs
- creer_livre('L3', 'Cartes', 48) construit {'code': 'L3', 'titre': 'Cartes', 'pages': 48}. Les clés nomment les champs ; leurs valeurs décrivent ce livre fictif.
- livre['pages'] vaut 48. Le test 'code' in livre est vrai, mais 'L3' in livre est faux : l'appartenance porte sur les clés, pas sur les valeurs.
- livre['pages'] = 52 remplace le nombre de pages. Il faut conserver la règle du schéma : entier strictement positif, même après la construction.
- Échanger l'ordre d'écriture des champs ne change pas cette lecture. À l'inverse, 0, −2, 3.5 ou True sont refusés par le constructeur pour pages.
Conclusion. Le nom du champ rend le sens lisible. Son domaine précise quelles valeurs sont acceptables ; les deux sont nécessaires.
Laboratoire de code
Languepython
Butconstruire et valider les fiches d'un catalogue de livres fictifs
Code solution
def creer_livre(code, titre, pages):
if not isinstance(code, str) or not code.strip():
raise ValueError("code absent")
if not isinstance(titre, str) or not titre.strip():
raise ValueError("titre absent")
if type(pages) is not int or pages <= 0:
raise ValueError("nombre de pages invalide")
return {"code": code, "titre": titre, "pages": pages}
def description(livre):
unite = 'page' if livre['pages'] == 1 else 'pages'
return f"{livre['code']} : {livre['titre']} ({livre['pages']} {unite})"
def total_pages(livres):
return sum(livre["pages"] for livre in livres)Tests
a = creer_livre("L1", "Algorithmes", 120)
b = creer_livre("L2", "Données", 80)
assert a == {"code": "L1", "titre": "Algorithmes", "pages": 120}
assert description(a) == "L1 : Algorithmes (120 pages)"
assert total_pages([a, b]) == 200
assert a is not b
try:
creer_livre('X', 'Fictif', True)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')
try:
creer_livre('X', 'Fictif', 0)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- les trois arguments sont contrôlés selon des domaines différents
- un dictionnaire neuf reçoit les clés code, titre et pages ; aucune position n'est à mémoriser
- description et total_pages lisent les champs par leur nom, ce qui préserve le sens si l'ordre d'écriture change
Clinique de bogue
Indice observéavec [code, titre, pages], le code tente d'additionner un entier au texte et inverse titre et pages
CauseLes positions n'expriment pas le schéma et le programmeur a mémorisé un ordre erroné. Des clés nommées rendent la lecture locale et permettent de valider la présence de chaque champ.
Étape du cours · 8 à 15 min
Dictionnaire : rechercher par clé et compter sans erreur d'initialisation
Un dictionnaire associe des clés uniques à des valeurs. {} crée un dictionnaire vide ; d[cle] lit la valeur associée et lève KeyError si la clé est absente. d[cle] = valeur ajoute ou remplace cette association. Les clés doivent être hachables : une chaîne, un entier ou un tuple d'entiers conviennent ; une liste ne convient pas. La clé n'est pas un numéro de position.
for cle in d et d.keys() parcourent les clés ; d.values() fournit les valeurs et d.items() les couples clé-valeur. Par exemple, pour d = {'A': 2, 'B': 1}, ces parcours donnent respectivement A puis B, 2 puis 1, et ('A', 2) puis ('B', 1). Python garantit l'ordre d'insertion depuis la version 3.7. Cela ne suffit pas à choisir un gagnant en cas d'égalité : la règle du problème reste à préciser.
d.get(mot, 0) renvoie zéro pour un mot absent, sans ajouter de clé. C'est l'affectation d[mot] = ... qui enregistre le nouveau compteur. frequences compte une liste de chaînes telles quelles : 'Chat' et 'chat' restent deux clés différentes. plus_frequent attend ces compteurs, non vides. En cas d'égalité, elle choisit la plus petite chaîne selon l'ordre lexicographique de Python, fondé sur les points de code Unicode, pas sur les règles alphabétiques d'une langue.
Un index de livres associe chaque code à un enregistrement existant. Deux livres de même code ne doivent pas s'écraser silencieusement : inverser_index refuse le doublon. Les enregistrements sont partagés avec la liste d'origine, pas copiés ; modifier un livre via l'index modifie donc ce même livre dans le catalogue.
Voir pour comprendre
Compter une occurrence sans perdre le passé
Exemple : compter successivement A, B puis A dans un dictionnaire.
- 1A arriveA n'existe pas : valeur initiale 0, puis compteur A = 1.
- 2B arriveB n'existe pas : compteur B = 1 ; A reste à 1.
- 3A revientA existe déjà : reprendre 1, ajouter 1, obtenir A = 2.
Lis le schéma. À chaque étape, indique quelles clés changent et lesquelles restent identiques.
get(cle, 0) donne le point de départ d'une clé absente. Remettre systématiquement le compteur à 1 perd les occurrences précédentes.
Exemples résolus et erreurs expliquées
Distinguer une valeur par défaut d'une nouvelle entrée
- Partons de d = {}. d.get('chat', 0) vaut 0, mais d reste {}. Une consultation avec valeur par défaut ne crée pas d'entrée.
- d['chat'] = d.get('chat', 0) + 1 crée l'association 'chat': 1. Une seconde occurrence remplace 1 par 2.
- Pour ['chat', 'rat', 'chat', 'rat'], on obtient {'chat': 2, 'rat': 2}. Les deux fréquences sont maximales : notre règle renvoie ('chat', 2), car 'chat' précède 'rat' dans l'ordre lexicographique.
- Pour un catalogue, deux enregistrements portant le code 'L1' ne peuvent pas occuper deux entrées distinctes sous cette même clé. On signale le doublon au lieu de remplacer le premier sans avertissement.
Conclusion. Une clé absente, une clé déjà présente et une égalité de fréquence sont trois situations différentes. Donne à chacune une règle explicite.
Laboratoire de code
Languepython
Butconstruire un index de fréquences et rendre le départage des égalités déterministe
Code solution
def frequences(mots):
compteurs = {}
for mot in mots:
compteurs[mot] = compteurs.get(mot, 0) + 1
return compteurs
def plus_frequent(compteurs):
if not compteurs:
raise ValueError("aucune fréquence")
maximum = max(compteurs.values())
candidats = [cle for cle, valeur in compteurs.items() if valeur == maximum]
return min(candidats), maximum
def inverser_index(enregistrements):
index = {}
for objet in enregistrements:
code = objet["code"]
if not isinstance(code, str) or not code.strip():
raise ValueError("code absent")
if code in index:
raise ValueError("code dupliqué")
index[code] = objet
return indexTests
assert frequences([]) == {}
assert frequences(["a", "b", "a"]) == {"a": 2, "b": 1}
assert plus_frequent({"b": 2, "a": 2, "c": 1}) == ("a", 2)
objets = [{"code": "X", "valeur": 3}, {"code": "Y", "valeur": 5}]
index = inverser_index(objets)
assert index["Y"]["valeur"] == 5
assert set(index.keys()) == {"X", "Y"}
assert index["X"] is objets[0]
assert frequences(["Chat", "chat"]) == {"Chat": 1, "chat": 1}
d = {}
assert d.get('absent', 0) == 0 and d == {}
try:
inverser_index([{"code": "X"}, {"code": "X"}])
except ValueError:
pass
else:
raise AssertionError("doublon accepté")Trace
- compteurs commence vide ; pour a, get(a,0) donne 0 puis la valeur 1 est associée
- pour b, une nouvelle entrée b:1 est construite ; pour le second a, get renvoie 1 puis stocke 2
- max(values) vaut 2 ; les candidats sont a et éventuellement d'autres clés, puis la règle min fixe le départage
Clinique de bogue
Indice observéle premier mot provoque KeyError parce qu'aucune valeur n'est encore associée à sa clé
CauseL'opération += lit la valeur précédente avant de l'incrémenter. Une nouvelle clé doit recevoir explicitement la valeur initiale 0 ou 1 avant toute lecture.
Poursuivre avec l’abonnement
Prédis les résultats, puis vérifie ton raisonnement
Les explications, schémas et exemples résolus restent en accès libre.
Avec l’abonnement, essaie les ateliers, réponds au quiz et reprends les idées signalées par tes erreurs. Les cartes du chapitre permettent ensuite de t’entraîner au rappel.
10 questions · 12 cartes. Ton bilan et tes révisions restent dans ce navigateur.
Comparer les formules Déjà abonné ? Se connecterVérifier et prolonger
Sources du cours
Édition Maxdecours · Vérifié le .
Spécialité NSI, Première générale · programme du BO spécial du 22 janvier 2019
- Programme officiel NSI Premièretypes construits, capacités attendues et limites de périmètre · consulté le 2026-09-05
- Éduscol, programmes et ressources NSIétat en vigueur et ressources d'accompagnement · consulté le 2026-09-05
- Éduscol, Types construits en Pythonp-uplets, listes, compréhensions, dictionnaires et exemples institutionnels · consulté le 2026-09-05
- Éduscol, Types mutables et problèmes associésaliasing, mutation, copie et erreurs caractéristiques · consulté le 2026-09-05
- Éduscol, p-uplets nommés et dictionnairesenregistrements, clés, valeurs et itérations · consulté le 2026-09-05
- Python, structures de donnéessémantique de référence des listes, p-uplets, compréhensions et dictionnaires · consulté le 2026-09-05
© 2026 Maxdecours.com · Comprendre et progresser