Question 1Parmi ces groupes, lequel ne contient que des types mutables ?
Types mutables et immuables
Apprends la distinction entre types mutables et immuables en Python pour éviter les bugs liés au partage de référence.
Pourquoi tu dois apprendre ça
Cet article n'est pas destiné aux grands débutants, mais le sujet est incontournable si tu veux vraiment comprendre la programmation en profondeur. C'est une histoire classique : un débutant tombe sur un bug lié à la mutabilité et passe des heures à déboguer.
En Python, tu peux croire que y = x relie simplement deux variables avec un signe égal, et découvrir que modifier l'une réécrit aussi l'autre. C'est ça, la mutabilité.
Ce chapitre éclaircit la différence entre « mutable » (modifiable) et « immuable » (non modifiable), et te montre comment copier en toute sécurité.
Un type qui permet de réécrire la variable elle-même (via append, une affectation d'élément, update, etc.) est mutable ; celui qui ne le permet pas est immuable.
list / dict / set sont mutables, et tout le reste (int / float / str / bool / tuple) est immuable.
Types immuables — modifier l'un n'affecte pas l'autre
Avec un type immuable (un type non modifiable), une fois que tu as passé la valeur avec y = x, modifier x ensuite n'a aucun effet sur y.
Par exemple, après x += 1, x vaut 11, mais y reste à la valeur d'origine 10.
# int est immuable
x = 10
y = x
x += 1
print(x) # 11
print(y) # 10 <- inchangé
# str est immuable aussi
x = "hello"
y = x
x = x + " world"
print(x) # hello world
print(y) # hello
# tuple est immuable aussi
x = ("a", "b")
y = x
x = ("c", "d")
print(x) # ('c', 'd')
print(y) # ('a', 'b')
Les variables Python sont des « étiquettes posées sur des boîtes »
Une variable en Python ne contient pas la valeur elle-même — c'est plutôt une étiquette qui pointe vers une donnée (une boîte) en mémoire. Quand tu écris y = x, Python ne crée pas une nouvelle boîte ; il colle juste une autre étiquette (y) sur la même boîte que celle vers laquelle x pointe.
- Types immuables : une réaffectation comme x = 11 déplace simplement l'étiquette x sur une autre boîte. y pointe toujours vers la boîte d'origine, donc sa valeur reste indépendante.
- Types mutables : une opération en place comme x.append(...) modifie la boîte partagée elle-même, donc le changement est visible aussi à travers y.
C'est la frontière entre immuable et mutable.
Types mutables — avec y = x, changer l'un change l'autre
Avec un type mutable (list / dict / set), en revanche, écrire y = x laisse y et x pointer sur la même boîte.
Si tu fais ensuite une opération qui réécrit le contenu, comme x.append(...), le changement apparaît aussi à travers y.
y = x ne crée pas de copie séparée — les deux noms pointent au même endroit.
Les opérations qui réécrivent le contenu, comme append, modifient la boîte partagée à laquelle les deux étiquettes font référence, donc le changement est visible à travers y aussi.
# list est mutable
x = ["a", "b"]
y = x # ajoute juste une autre étiquette y à la même liste
x.append("c") # réécrit le contenu directement
print(x) # ['a', 'b', 'c']
print(y) # ['a', 'b', 'c'] <- y a grandi aussi !
# remove se comporte pareil
x.remove("b")
print(y) # ['a', 'c'] <- disparaît de y aussi
# dict et set montrent le même comportement
d = {"k": 1}
e = d
e["new"] = 99
print(d) # {'k': 1, 'new': 99} <- d a grandi aussi
Pourquoi le partage est-il le comportement par défaut ?
Si y = x copiait tout le contenu à chaque fois, alors quand, par exemple, x contient des millions d'enregistrements récupérés d'une base de données, la mémoire et le temps d'exécution exploseraient vite.
En Python, un nom de variable n'est pas la valeur elle-même — c'est une étiquette qui pointe vers un emplacement en mémoire.
Tu ne peux pas changer ce mécanisme, donc c'est à toi (celui qui écrit) de l'utiliser avec prudence.
Utilise copy() pour obtenir une version indépendante
Quand tu veux garder les données d'origine et créer une version séparée, utilise la méthode copy().
Écrire y = x.copy() copie le contenu dans une nouvelle boîte et la donne à y, donc les modifications ultérieures de x n'affectent pas y.
y = x.copy() alloue à ce moment-là une nouvelle zone mémoire.
Ensuite, réécrire le contenu de x avec x.append(...) ou similaire n'a aucun effet sur y.
# list / dict / set ont tous .copy()
x = ["apple", "lemon"]
y = x.copy()
x.append("grape")
print(x) # ['apple', 'lemon', 'grape']
print(y) # ['apple', 'lemon'] <- pas affecté
# dict.copy() fonctionne pareil
d = {"a": 1, "b": 2}
e = d.copy()
d["c"] = 3
print(d) # {'a': 1, 'b': 2, 'c': 3}
print(e) # {'a': 1, 'b': 2} <- pas affecté
# set.copy() fonctionne pareil
s = {1, 2}
t = s.copy()
s.add(3)
print(s) # {1, 2, 3}
print(t) # {1, 2} <- pas affecté
# list a d'autres façons de copier
x = ["apple", "lemon"]
y1 = list(x) # passer par le constructeur donne une nouvelle liste
y2 = x[:] # copie intégrale via slice (du début à la fin)
Attention quand ta liste contient d'autres listes
copy() ne construit qu'une nouvelle boîte extérieure. Les valeurs mutables à l'intérieur (comme des listes dans une liste) restent partagées. On appelle ça une copie superficielle (shallow copy).
Fais attention avec les données imbriquées.
Dans cet article, tu as appris la différence entre types mutables et immuables, et comment copy() te donne une version indépendante.
L'idée qu'un nom de variable n'est pas la valeur elle-même mais une étiquette qui pointe vers un emplacement en mémoire se retrouve aussi dans d'autres langages, pas seulement Python. Quand tu manipules des types mutables, glisse un copy().
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Quelle est la valeur de b après l'exécution du code suivant ?
``
a = [1, 2, 3]
b = a
a.append(4)
Question 3Tu veux garder le contenu de la liste d'origine a et obtenir une version indépendante b. Quelle est la façon la plus appropriée de l'écrire ?