Simple understanding of deep copy and shallow copy in Python

I. Introduction

A deep copy recursively creates a completely independent copy of the object, including all nested objects , while a shallow copy only copies references to nested objects , not the nested objects themselves.

Simply put, both copy the original object, so when using the is operator to compare the old and new objects, both return False (both open up new memory); the difference between the two is whether the nested object is Recursive copying . Shallow copy does not copy and allocate new memory for nested objects, and returns True when using is to compare nested objects; while deep copy opens up nested objects to copy and allocate new memory, and uses is to compare nested objects Returns False.

An example is as follows, we perform deep copy and shallow copy on the head node of the linked list respectively:

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

In terms of code implementation, deep copy can be realized by using the deepcopy method of the copy library; shallow copy can be implemented in many other ways besides using the copy method of the copy library, which we will introduce next.


II. List

A. First of all, it should be noted that for the commonly used equal sign assignment operation, this operation does not make any copies , but only creates a new reference to the existing object:

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

B. Slicing a list is a shallow copy operation:

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

C. Shallow copy does not copy nested objects:

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. Deep copy will only copy nested objects:

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. The constructor using the data type itself is still a shallow copy:

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. The new list returned by modifying the list is also a shallow copy (shallow copy first and then modify):

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. String

A. Strings in Python are immutable objects. So, if you do a full slice[:], you can see that the string itself is not modified by this process. Then Python will only directly record the reference of the original string object at this time, without any copying . From the perspective of design motivation, since it cannot be modified itself, and the slicing operation is not modified, the meaning of copying is not great, so it is not copied at all:

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

B. The above conclusions also apply to the "false modification" of the string, and no copy will be made at this time:

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

C. If you want to copy, you have to substantially modify the string. If the slice operation changes the content of the original string, since the string is immutable, only a new memory can be opened to store the modified string. At this point the copying process is performed. Note that since the string itself cannot nest objects, there is no distinction between deep copy and shallow copy:

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

D. Using the constructor str does not make any copies, but creates another reference to the original string object:

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

E. Neither copy nor deepcopy can copy the content of the string, only a new reference will be added:

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

Guess you like

Origin blog.csdn.net/qq_40714949/article/details/132297074