
En Python, vous pouvez faire une copie superficielle et profonde avec la méthode copy() de list , dictionary, etc., ou les fonctions copy() et deepcopy() du module copy.
Cet article décrit le contenu suivant.
- Copie superficielle et copie profonde en Python
- Affectation à une autre variable
- Copie superficielle:
copy(), copy.copy(), etc.
- méthode copy() de la liste, du dictionnaire, etc.
- Tranche
- liste(), dict(), etc.
- copie.copie()
- Copie profonde :
copy.deepcopy()
Voici un résumé des différences entre l’affectation à une autre variable, la copie superficielle et la copie complète.
import copy
l = [0, 1, [2, 3]]
l_assign = l # assignment
l_copy = l.copy() # shallow copy
l_deepcopy = copy.deepcopy(l) # deep copy
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_assign)
# [0, 100, [200, 3]]
print(l_copy)
# [0, 1, [200, 3]]
print(l_deepcopy)
# [0, 1, [2, 3]]
Copie superficielle et copie profonde en Python
La documentation officielle de Python décrit la copie superficielle et la copie profonde comme suit.
La différence entre copie superficielle et copie profonde n’est pertinente que pour les objets composés (objets qui contiennent d’autres objets, comme des listes ou des instances de classe) :
Pour les objets dans des objets mutables tels que des listes et des dictionnaires (= éléments dans une liste ou valeurs dans un dictionnaire), la copie superficielle insère des références et la copie profonde insère des copies. Dans le cas des références, il s’agit du même objet, donc si l’une d’elles est modifiée, l’autre est également modifiée.
Affectation à une autre variable
Voyons d’abord ce qui se passe lors de l’affectation à une variable.
Lorsqu’un objet modifiable tel qu’une liste ou un dictionnaire est affecté à plusieurs variables, la mise à jour d’une variable (= modification, ajout ou suppression d’éléments, etc.) mettra également à jour les autres variables.
l1 = [0, 1, [2, 3]]
l2 = l1
print(l1 is l2)
# True
l1[1] = 100
l1[2][0] = 200
print(l1)
# [0, 100, [200, 3]]
print(l2)
# [0, 100, [200, 3]]
print(l1 is l2)
# True
Comme vous pouvez le voir dans le résultat de is, les deux variables font référence au même objet avant et après la modification de la valeur.
Pour créer une copie au lieu d’une référence du même objet, utilisez la méthode copy() ou la fonction copy.deepcopy() décrite ci-dessous.
En revanche, dans le cas d’objets immuables tels que les nombres int, float et strings str, la valeur de l’objet ne peut pas être mise à jour. Lorsqu’elles sont affectées, les deux variables sont le même objet, mais lorsque l’une est mise à jour avec une nouvelle valeur, elle devient un objet différent et l’autre reste la même.
i1 = 1
i2 = i1
print(i1 is i2)
# True
i1 += 100
print(i1)
# 101
print(i2)
# 1
print(i1 is i2)
# False
Copie superficielle:copy(), copy.copy(), etc.
méthode copy() de la liste, du dictionnaire, etc.
La méthode copy() est fournie pour les listes, les dictionnaires, etc. La méthode copy() fait une copie superficielle.
Comme mentionné ci-dessus, une copie superficielle insère une référence à un objet dans l’objet d’origine. Par exemple, dans le cas d’une copie superficielle d’une liste, la liste elle-même est un objet différent, mais ses éléments sont des références aux mêmes objets dans les éléments de la liste d’origine.
l = [0, 1, [2, 3]]
l_copy = l.copy()
print(l is l_copy)
# False
print(l[2] is l_copy[2])
# True
Par conséquent, si les éléments sont modifiables, lorsque l’un est mis à jour, l’autre est également mis à jour. Dans le cas d’un immuable, lorsqu’il est mis à jour avec une nouvelle valeur, il devient un objet différent et l’autre reste l’original.
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_copy)
# [0, 1, [200, 3]]
print(l[2] is l_copy[2])
# True
La même chose s’applique non seulement à une liste de listes comme dans l’exemple ci-dessus, mais également à une liste de dictionnaires, de dictionnaires imbriqués (un dictionnaire qui a des dictionnaires comme valeurs), etc.
Tranche
Les tranches pour les types de séquence modifiables, tels que les listes, font également des copies superficielles.
Par exemple, l’application de la tranche [:] qui spécifie tous les éléments crée une copie superficielle de toute la liste.
l = [0, 1, [2, 3]]
l_whole_slice = l[:]
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_whole_slice)
# [0, 1, [200, 3]]
Depuis que la méthode copy() a été ajoutée aux types de séquence mutables dans Python 3.3, la technique consistant à faire une copie superficielle avec [:] était souvent utilisée auparavant. Pour le nouveau code, il serait préférable d’utiliser la méthode copy () pour clarifier vos intentions.
Une tranche pour une pièce crée également une copie superficielle.
l = [0, 1, [2, 3]]
l_slice = l[1:]
print(l_slice)
# [1, [2, 3]]
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_slice)
# [1, [200, 3]]
Si vous voulez faire une copie complète, vous pouvez utiliser la fonction copy.deepcopy() pour la tranche.
liste(), dict(), etc.
Vous pouvez faire une copie superficielle d’une liste ou d’un dictionnaire en passant une liste à list() ou un dictionnaire à dict().
l = [0, 1, [2, 3]]
l_list = list(l)
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_list)
# [0, 1, [200, 3]]
copie.copie()
Il est aussi possible de faire une copie superficielle avec la fonction copy() du module copy.
l = [0, 1, [2, 3]]
l_copy = copy.copy(l)
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_copy)
# [0, 1, [200, 3]]
Utilisez copy.copy() si vous voulez faire une copie superficielle d’un objet pour lequel la méthode copy() n’est pas fournie.
Copie profonde :copy.deepcopy()
Pour faire une copie complète, utilisez la fonction deepcopy() du module de copie.
l = [0, 1, [2, 3]]
l_deepcopy = copy.deepcopy(l)
print(l is l_deepcopy)
# False
print(l[2] is l_deepcopy[2])
# False
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_deepcopy)
# [0, 1, [2, 3]]
Dans une copie complète, des copies sont insérées à la place des références aux objets, donc la modification de l’une ne modifie pas l’autre.
Voici un exemple d’application de la fonction deepcopy() à une tranche.
l = [0, 1, [2, 3]]
l_slice_deepcopy = copy.deepcopy(l[1:])
print(l_slice_deepcopy)
# [1, [2, 3]]
l[1] = 100
l[2][0] = 200
print(l)
# [0, 100, [200, 3]]
print(l_slice_deepcopy)
# [1, [2, 3]]