Compréhension simple de la copie profonde et de la copie superficielle en Python

Introduction

Une copie complète crée de manière récursive une copie complètement indépendante de l'objet, y compris tous les objets imbriqués , tandis qu'une copie superficielle copie uniquement les références aux objets imbriqués , et non les objets imbriqués eux-mêmes.

En termes simples, les deux copient l'objet d'origine, donc lors de l'utilisation de l'opérateur is pour comparer les anciens et les nouveaux objets, les deux renvoient False (les deux ouvrent une nouvelle mémoire) ; la différence entre les deux est de savoir si l'objet imbriqué est une copie récursive . La copie superficielle ne copie pas et n'alloue pas de nouvelle mémoire pour les objets imbriqués et renvoie True lorsqu'elle est utilisée pour comparer des objets imbriqués ; tandis que la copie profonde ouvre des objets imbriqués pour copier et allouer de la nouvelle mémoire et utilise pour comparer des objets imbriqués Renvoie False.

Un exemple est le suivant, nous effectuons respectivement une copie profonde et une copie superficielle sur le nœud principal de la liste chaînée :

# 原链表 ↓
a1 -> b1 -> c1 -> d1 -> e1
# 浅拷贝 ↓ 对于嵌套对象b1, c1, ..., 直接采用了原有引用
a2 -> b1 -> c1 -> d1 -> e1
# 深拷贝 ↓ 对于嵌套对象,同样开辟了内存空间将其复制
a2 -> b2 -> c2 -> d2 -> e2

En termes d'implémentation de code, la copie profonde peut être réalisée en utilisant la méthode de copie profonde de la bibliothèque de copie ; la copie superficielle peut être implémentée de nombreuses autres manières en plus d'utiliser la méthode de copie de la bibliothèque de copie, que nous présenterons ensuite.


II.Liste

A. Tout d'abord, il convient de noter que pour l'opération d'affectation de signe égal couramment utilisée, cette opération ne fait aucune copie , mais crée uniquement une nouvelle référence à l'objet existant :

arr1 = [1, 2, 3, 4]
arr2 = arr1
print(arr2 is arr1)  # True
arr2[0] = 0
print(arr1)  # [0, 2, 3, 4]

B. Le découpage d'une liste est une opération de copie superficielle :

arr1 = [1, 2, 3, 4]
arr2 = arr1[:]
print(arr2 is arr1)  # False
arr2[0] = 0
print(arr1)  # [1, 2, 3, 4]

C. La copie superficielle ne copie pas les objets imbriqués :

arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = arr1[:]
print(arr2 is arr1)  # False(最外层被复制)
print(arr2[-1] is arr1[-1])  # True(嵌套对象没有被复制)
arr2[-1][0] = 0 
print(arr1)  # [1, 2, 3, [0, 5, 6]](被修改)

D. La copie en profondeur ne copiera que les objets imbriqués :

import copy
arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = copy.deepcopy(arr1)
print(arr2 is arr1)   # False
print(arr2[-1] is arr1[-1])   # False(嵌套对象也被复制)
arr2[-1][0] = 0 
print(arr1)   # [1, 2, 3, [4, 5, 6]](未修改)

E. Le constructeur utilisant le type de données lui-même est toujours une copie superficielle :

arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = list(arr1)  # 使用构造器创建新对象, 属于浅拷贝
print(arr2 is arr1)   # False
print(arr2[-1] is arr1[-1])  # True
arr2[-1][0] = 0 
print(arr1)   # [1, 2, 3, [0, 5, 6]]

F. La nouvelle liste renvoyée en modifiant la liste est également une copie superficielle (copie superficielle d'abord, puis modification) :

arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = arr1 + []  # 先浅拷贝再修改
print(arr2 is arr1)  # False
print(arr2[-1] is arr1[-1])  # True
arr2[-1][0] = 0 
print(arr1)  # [1, 2, 3, [0, 5, 6]]

III. Chaîne

A. Les chaînes en Python sont des objets immuables. Par conséquent, si vous effectuez une tranche complète[:], vous pouvez voir que ce processus ne modifie pas la chaîne elle-même. Ensuite, Python n'enregistrera directement que la référence de l'objet chaîne d'origine à ce moment, sans aucune copie . Du point de vue de la motivation de conception, puisqu'il ne peut pas être modifié lui-même et que l'opération de découpage n'est pas modifiée, la signification de la copie n'est pas grande, donc elle n'est pas copiée du tout :

s1 = "1234"
s2 = s1[:]
print(s2 is s1)  # True(引用的内容相同)

B. Les conclusions ci-dessus s'appliquent également à la "fausse modification" de la chaîne, et aucune copie ne sera faite pour le moment :

s1 = "1234"
s2 = s1 + ""
print(s2 is s1)  # True(没有进行实质修改)

C. Si vous souhaitez copier, vous devez modifier considérablement la chaîne. Si l'opération slice modifie le contenu de la chaîne d'origine, puisque la chaîne est immuable, seule une nouvelle mémoire peut être ouverte pour stocker la chaîne modifiée. À ce stade, le processus de copie est exécuté. Notez que puisque la chaîne elle-même ne peut pas imbriquer des objets, il n'y a pas de distinction entre copie profonde et copie superficielle :

s1 = "1234"
s2 = s1[::-1][::-1] # 进行两次修改,翻转两次
print(s2 is s1) # False
print(s2) # 1234
s3 = s1 + "5" 
print(s3 is s1) # False

D. L'utilisation du constructeur str ne fait aucune copie, mais crée une autre référence à l'objet chaîne d'origine :

s1 = "1234"
s2 = str(s1)
print(s2 is s1)  # True

E. Ni copy ni deepcopy ne peuvent copier le contenu de la chaîne, seule une nouvelle référence sera ajoutée :

import copy
s1 = "1234"
s2 = copy.copy(s1)
s3 = copy.deepcopy(s1)
print(s2 is s1)  # True
print(s3 is s1)  # True

Je suppose que tu aimes

Origine blog.csdn.net/qq_40714949/article/details/132297074
conseillé
Classement