Details on deep and shallow copies of Python objects

  • 2020-04-02 14:01:12
  • OfStack

This article content is in "Python core programming 2" to see, the feeling is very useful to write out, for your reference!

Shallow copy

First we use two ways to copy objects, one is to slice them and the other is to use factory methods. Then use the id function to see their identifiers


# encoding=UTF-8
 
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
    print id(x)
 
35217032
35227912
29943304

 
They all have different ids. According to the normal judgment, the three objects with different ids should all be independent. So let's change their names first

# encoding=UTF-8
 
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
    print id(x)
    
a[0] = 'lisi'
b[0] = 'zhangsan'
 
print a
print b
 
35217032
35227912
33547784
['lisi', ['age', 18]]
['zhangsan', ['age', 18]]

Object a and object b are given different names, so let's change the age of object a

# encoding=UTF-8
 
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
for x in obj,a,b:
    print id(x)
    
a[0] = 'lisi'
b[0] = 'zhangsan'
 
print a
print b
 
a[1][1] = 25
 
print a
print b
 
35217032
35227912
29943304
['lisi', ['age', 18]]
['zhangsan', ['age', 18]]
['lisi', ['age', 25]]
['zhangsan', ['age', 25]]

Careful friends should see that changing a[0] element and b[0] element do not affect each other, why changing a[1][1] element will affect b[1][1] element?
To solve this problem, you must first understand the deep and shallow copies. In the above example, the a and b we created are shallow copies of obj objects, where the first element is that the string is of an immutable type and the second element is that the list is of a mutable type. So when we copy the object, the string is copied by the display copy to recreate a string, and the list is just a copy of the reference, so changing the elements of the list affects all the reference objects. From the following id values, you can see

# encoding=UTF-8
 
obj = ['name',['age',18]]
a=obj[:]
b=list(obj)
 
for x in obj,a,b:
    print id(x[0]),id(x[1])
print
 
a[0] = 'lisi'
b[0] = 'zhangsan'
 
for x in obj,a,b:
    print id(x[0]),id(x[1])
print
 
a[1][1] = 25
b[1][1] = 30
 
for x in obj,a,b:
    print id(x[0]),id(x[1])
print
 
32564088 34496008
32564088 34496008
32564088 34496008
 
32564088 34496008
34574704 34496008
33970672 34496008
 
32564088 34496008
34574704 34496008
33970672 34496008

When we copy the object, we can see that the id of all the elements is always the same, we changed the first string element of a and b respectively, because the string is an immutable object, so the change is equal to the new creation, so a and b's first string element id is not consistent. However, the second element of a and b is a list variable object, so no matter how any id value is modified, it represents a pointer and always affects the value of other reference objects.
Therefore, why changing the age of object a will affect the age value of object b, or changing the age value of object b will also affect the age value of object a, including obj.

Deep copy

All of the above are shallow copies, so we want to copy the object is independent, do not affect other values when the modification, we call this deep copy. To implement deep copy, we need to refer to a copy module. Copy module has two functions available, one is copy shallow copy; The other is deepcopy deepcopy.


# encoding=UTF-8
import copy
obj = ['name',['age',18]]
a=copy.deepcopy(obj)
b=copy.deepcopy(obj)
 
for x in a,b:
    print id(x[0]),id(x[1])
print
 
a[1][1] = 25
b[1][1] = 30
 
print a
print b
 
33612664 35477256
33612664 35477640
 
['name', ['age', 25]]
['name', ['age', 30]]

With a deep copy, the id of the list element is inconsistent, indicating a separate object, and changing the value of any one list element does not affect the other objects.

Here are a few notes on copying operations:
First, non-container types (such as Numbers, strings, and other "yard" types of objects, such as code, types, and range objects) are not copied.

Second, if the primitive variable contains only atomic-type objects, a deep copy of it will not occur.
Let's change the above example to a primitive and try using deep copy


# encoding=UTF-8
import copy
obj = ['name',('age',18)]
a=copy.deepcopy(obj)
b=copy.deepcopy(obj)
 
for x in a,b:
    print id(x),id(x[1])
print
 
34703752 34693000
34756616 34693000


Related articles: