Pourquoi ce code produit-il un résultat surprenant ?
a = [1, 2, 3]
b = a
b.append(4)
print(a)La liste a contient maintenant 4 alors qu'on n'a modifié que b. Ce chapitre explique pourquoi, et comment éviter ce piège.
Variables et objets : le modèle Python
En Python, une variable n'est pas une case mémoire qui contient une valeur. C'est une étiquette qui pointe vers un objet en mémoire.
x = 42Ce qui se passe :
- Python crée un objet entier
42en mémoire. - L'étiquette
xest attachée à cet objet.
x ────► [ 42 ]On peut visualiser cette référence avec la fonction id() qui renvoie l'identifiant unique d'un objet en mémoire :
x = 42
print(f"x pointe vers l'objet {id(x)}")L'alias : deux étiquettes, un seul objet
Quand on écrit b = a, on ne copie pas les données. On crée une nouvelle étiquette qui pointe vers le même objet.
a = [1, 2, 3]
b = a
print(f"id(a) = {id(a)}")
print(f"id(b) = {id(b)}")
print(f"a et b pointent vers le même objet : {a is b}")a ────┐
├───► [ 1, 2, 3 ]
b ────┘On dit que a et b sont des alias — deux noms pour le même objet. Toute modification via b est aussi visible par a :
a = [1, 2, 3]
b = a
b.append(4) # on modifie L'OBJET via b
print("a :", a) # a voit la modification : même objet !
print("b :", b)L'opérateur is — identité d'objet
L'opérateur is teste si deux variables pointent vers le même objet (identité), alors que == teste si leurs valeurs sont égales (égalité).
a = [1, 2, 3]
b = a # alias
c = [1, 2, 3] # nouvel objet, même contenu
print("a == b :", a == b) # True : même contenu
print("a is b :", a is b) # True : même objet
print("a == c :", a == c) # True : même contenu
print("a is c :", a is c) # False : objets différents !a ────┐
├───► [ 1, 2, 3 ] ← même objet
b ────┘
c ────────► [ 1, 2, 3 ] ← autre objet, même contenuCréer une vraie copie
Pour obtenir une copie indépendante d'une liste, on a plusieurs options :
Méthode 1 : slicing [:]
a = [1, 2, 3]
b = a[:] # copie par slicing
b.append(4)
print("a :", a) # inchangé
print("b :", b)
print(a is b) # False : objets différentsMéthode 2 : constructeur list()
a = [1, 2, 3]
b = list(a) # même effet
b.append(4)
print("a :", a)
print("b :", b)Méthode 3 : méthode .copy()
a = [1, 2, 3]
b = a.copy()
b.append(4)
print("a :", a)
print("b :", b)Tableau des techniques de copie
| Méthode | Copie de | Notes |
|---|---|---|
b = a[:] |
liste, tuple, str | Slicing complet |
b = list(a) |
liste | Explicit |
b = a.copy() |
liste, dict, set | Méthode dédiée |
b = dict(a) |
dict | — |
b = set(a) |
set | — |
b = a |
❌ alias, pas une copie ! | Piège |