I encountered some problems this week, and then I realized that if the basic knowledge has not been consolidated for a period of time, there are still forgotten parts that still need to be reviewed. I will make a note here to record it
Previous Continue
Let’s briefly describe the problem encountered. The requirement is to write the results of 2 prints
As you can see, a points to a list list object, in Python, such an assignment statement actually means that a points to the memory address where the list is located, which can be regarded as a concept similar to a pointer.
And b, please note that it wraps the a object into a list and multiplies it by 5, so b should look like a big list with all the elements in it. When the a object After the append operation is performed, in fact, the implicit meaning is that the list in the memory has been modified, and all objects that reference this object will change
I print out the id of a, and , and print the id of element a contained in the object b, so that you can see that in the list b, the id of each element is the same as aWe can see that the id (memory address) of object a is 10892296. Although b wraps a into a new list, this element still refers to the object with the same address. This can be explained by the following figure
After that, we performed the append operation on a. Since list is a variable object, its memory address has not changed, but the reference to this address in the memory All objects will be changed together, which can be seen from the lower half of the dividing line in the test chart above.
This leads to a review of the Python reference mechanism and shallow copy and deep copy
Python’s reference mechanism
Reference mechanism case 1
From the above example, we can see that python Pass by reference, the final result is to have two objects refer to the contents of the same area in the memory
So let's take a look at the following example
B passes A, and also references the id of 17446024 The content of the address and the ID (memory address) of the two are exactly the same
So, through the operation of A A[0]=3 or A[3].append(6), it will be correct The contents in this memory are modified (because list is a variable object, so the memory address will not change, which will be discussed later)
This is the most basic reference case (in addition, since A and B all points to the same memory address, so the content modified by B can also be reflected on A)
Reference mechanism case 2
Let’s look at another case
Looking at the question, it seems that element 2 will be replaced with the list itself. The result may be A=[1,[1,2,3],3]
But it’s not! ! You can see that in the red box, there are infinite number of nested
Why is this happening?
In fact, it is because A points to the list [1,2,3]. In this example, only the second element of A points to the A object itself, so it is only the second element of A. The structure has changed! However, A still points to that object
We can see by printing the id of A that its pointing has not changed! ! Let’s take a look, the direction of A has not changed
Then if we want to achieve the final output effect, it is [ 1, [1,2,3],3], how should we operate it?
Here, we will use shallow copy. The usage can be as follows
Shallow copy and deep copy
Shallow copy
Now, let’s talk about shallow copy and deep copy. The above method actually only performs shallow copy, shallow copy, which means that it copies the original referenced object, but no longer references the same object address
Look at the example below. B performs a shallow copy through the B = A[:] operation. You can see that after the shallow copy, the memory addresses referenced by A and B are already different
However, the reference addresses of the elements inside A and B are still the same, so be very careful about this! There is a difference! ! !
The difference in the reference memory addresses of A and B means that the operation you perform on B will not affect A.
Shallow copy summary:
So shallow copy can be summarized as copying a reference, the new object and the original The object references are distinguished, but the address references of the internal elements are still the same
But shallow copying will also have problems. What is the problem? It is when there is nesting. For example, as you can see in the following situation, I assigned a shallow copy of A to B, so that the IDs (memory addresses) of A and B are different.
So, when I modify A[0]=8, B will not be affected, because A and B are independent references, but there is a nested list in the middle [4 ,5,6]
We can understand this [4,5,6] as: A and B still reference together, that is, for the second elements of A and B, they still point to the same A memory address.
In addition, since int is an immutable type, after changing A[0] to 8, its reference address will change! It is distinguished from the reference of the element B[0].
Deep Copy
So how to face such a situation? We need to use the copy module in the python module
The copy module has 2 functions
1: copy.copy (the object you want to copy): This is a shallow copy, and the previous one The nature of the [:] operation on the list is the same
2: copy.deepcopy (the object you want to copy): This is a deep copy, except that it will generate a new object just like the shallow copy. References, and for internal elements, new references will be generated to separate them independently.
Look at the example below, when you assign a deep copy of A to B, they can be said to be completely independent. , whether you modify the immutable elements in A, or modify the nested mutable elements in A, the result will not affect B
My understanding is: deep copy can be called recursive copy, He will copy all nested variable elements and then reference them independently.
Deep copy summary:
The effect of deep copy is the same as that of shallow copy. In addition to generating a new reference from the object's reference, it will help you open all the nested elements one by one.
I drew 2 pictures myself Figure to show the difference between the effects of shallow copy and deep copy
It should be noted that although after shallow copy, the reference address of the immutable elements in the list is still the same, but because they are immutable elements, Therefore, after any immutable element is changed, the reference address will be new without affecting the original reference address.
##Summary
So, here we go, shallow copy And the mechanism of deep copy is basically understood.
There are also special circumstances that need to be explained
For immutable types: int, str, tuple, float and other elements, there is no copy. After they are modified, the reference address is Directly changed, as shown below
However, if there are nested variable types inside the immutable type, you can still use deep copy
Also a reminder, the method we usually use most is direct assignment (or direct passing of references), such as the following example
He combines a and b Two variable elements point to a memory address at the same time, so any change will affect a and b
Finally
Variable type: list , set, dict
Immutable types: int, str, float, tuple
Shallow copy method: [:], copy.copy(), use factory function (list/dir/set )
Deep copy method: copy.deepcopy()
The above is the detailed content of Detailed explanation of Python shallow copy, deep copy and reference mechanism. For more information, please follow other related articles on the PHP Chinese website!