Python学习-赋值、浅copy和深copy

Python Copy:

在Python语言中,分为浅拷贝和深拷贝两种形式,也就是官方文档中的Shadow copy和Deep copy。在对简单的对象(object)进行复制时,两者没有区别,如下面的代码所示:

 1 #简单对象的浅copy和深copy对比
 2 import copy
 3 list1 = [1,2,3,4,5]
 4 #浅复制
 5 Shadow_copy_list1 = copy.copy(list1)
 6 print(list1)   #[1, 2, 3, 4, 5]
 7 print(Shadow_copy_list1)    #[1, 2, 3, 4, 5]
 8 #对原对象元素进行修改:列表末尾添加'6'
 9 list1.append(6)
10 print(list1)         #[1, 2, 3, 4, 5, 6]
11 print(Shadow_copy_list1)    #[1, 2, 3, 4, 5]
12 print(id(list1))      #地址:2483079696328
13 print(id(Shadow_copy_list1))      #地址:2483079778504
14 
15 #深复制
16 Deep_copy_list1 = copy.deepcopy(list1)
17 print(list1)     #[1, 2, 3, 4, 5]
18 print(Deep_copy_list1)    #[1, 2, 3, 4, 5]
19 #对原对象元素进行修改:列表末尾添加'6'
20 list1.append(6)
21 print(list1)   #[1, 2, 3, 4, 5, 6]
22 print(Deep_copy_list1)    #[1, 2, 3, 4, 5]
23 
24 print(id(list1))    #地址:1927356387400
25 print(id(Deep_copy_list1))    #地址:1927356387592

从简单对象的浅copy和深copy可以看出,对原列表中的元素进行修改,copy的对象里面的元素不会发生改变。

对于浅copy和深copy,在复杂对象的copy中会有所区别,如下程序所示:

 1 #复杂对象的浅copy和深copy对比
 2 import copy
 3 list1 = [1,2,3,[4,5]]
 4 #浅copy
 5 Shadow_copy_list1 = copy.copy(list1)
 6 list1[3][0] = 7
 7 print(list1)    #[1, 2, 3, [7, 5]]
 8 print(Shadow_copy_list1)     #[1, 2, 3, [7, 5]]
 9 print(id(list1))     #地址:2201242341640
10 print(id(Shadow_copy_list1))    #地址:2201242342920
11 
12 list1[3][0] = 4   #将列表恢复为初始列表
13 #深copy
14 Deep_copy_list1 = copy.deepcopy(list1)
15 list1[3][0] = 7
16 print(list1)    #[1, 2, 3, [7, 5]]
17 print(Deep_copy_list1)    #[1, 2, 3, [4, 5]]
18 print(id(list1))    #地址:2201242341640
19 print(id(Deep_copy_list1))     #地址:2201242342856

从复杂对象的浅copy和深copy可以看出,当浅copy时,如果对复杂对象的子对象元素进行修改,原列表和copy的列表里面的子对象元素都会产生变化,但是当深copy时,若复杂对象的子对象元素发生了变化,copy的对象的所有元素都不会发生变化。这是什么原因呢,这是因为浅拷贝只复制一层对象的属性,而深复制则递归复制了所有层级。

1、copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。

2、copy.deepcopy 深拷贝 拷贝对象及其子对象

(深copy)

深copy新建一个对象重新分配内存地址,在内存中生成完全一模一样的内容。

(浅copy)

浅copy也会对复制后的列表重新分配内存地址。但是在浅copy中,对于列表里面的元素,浅copy复制的是元素的内存地址,相当于引用,此时的子对象属于公共对象,浅copy如果对象中有引用其他的对象,如果对这个子对象进行修改,子对象的内容就会发生更改。

总结:

  1. 在简单对象中,无论是浅copy还是深copy,原对象里面元素的变化不会引起复制对象里面的元素的变化。
  2. 在复杂对象中,原对象的子对象元素发生变化,浅copy的对象里面的子对象元素也会产生变化,此时该子对象相当于镜像文件,对于引用它的对象,都会产生影响,而在深copy中,由于深copy是对所有的元素进行了复制,所以原对象里面子对象元素的变化不会导致复制对象里面元素的变化。

Python 赋值:

简单对象的赋值、浅copy和深copy对比:

 1 #简单对象的赋值、浅copy和深copy对比
 2 import copy
 3 list1 = [1,2,3,4,5]
 4 New_list1 = list1
 5 Shadow_copy_list1 = copy.copy(list1)
 6 Deep_copy_list1 = copy.deepcopy(list1)
 7 #对原对象元素进行修改:列表末尾添加'6'
 8 list1.append(6)
 9 #原列表
10 print(list1)    #[1, 2, 3, 4, 5, 6]
11 print(id(list1))    #地址:1913255661704
12 #赋值列表
13 print(New_list1)    #[1, 2, 3, 4, 5, 6]
14 print(id(New_list1))     #地址:1913255661704
15 #浅copy列表
16 print(Shadow_copy_list1)    #[1, 2, 3, 4, 5]
17 print(id(Shadow_copy_list1))     #地址:1913255661896
18 #深copy列表
19 print(Deep_copy_list1)    #[1, 2, 3, 4, 5]
20 print(id(Deep_copy_list1))     #地址:1913255663176

从程序运行结果可以看出,简单对象中,若原列表元素发生改变,则通过赋值的新列表元素也会改变,而浅copy和深copy的列表元素均不会发生变化。可以认为赋值是将原对象上贴上两个标签,如程序中的list1标签和New_list1两个标签,使用的也是内存中的同一块地址,列表中元素的变化,则两个list均会产生变化。而使用copy进行复制的则不同了,不管是浅copy和深copy,都会重新在内存中分配一块地址,这样原列表中元素的变化,复制的列表中不会产生变化。

复杂对象的赋值、浅copy和深copy对比:

 1 #复杂对象的赋值、浅copy和深copy对比
 2 import copy
 3 list1 = [1,2,3,[4,5]]
 4 New_list1 = list1
 5 Shadow_copy_list1 = copy.copy(list1)
 6 Deep_copy_list1 = copy.deepcopy(list1)
 7 #对原对象元素进行修改:将列表中第4个元素中的'4'更改为'7'
 8 list1[3][0] = 7
 9 #原列表
10 print(list1)    #[1, 2, 3, [7, 5]]
11 print(id(list1))    #地址:1975516434760
12 #赋值列表
13 print(New_list1)    #[1, 2, 3, [7, 5]]
14 print(id(New_list1))     #地址:1975516434760
15 #浅copy列表
16 print(Shadow_copy_list1)    #[1, 2, 3, [7, 5]]
17 print(id(Shadow_copy_list1))     #地址:1975516436040
18 #深copy列表
19 print(Deep_copy_list1)    #[1, 2, 3, [4, 5]]
20 print(id(Deep_copy_list1))     #地址:1975516435976

从程序运行结果可以看出,对复杂对象的子对象元素进行修改时,通过赋值的列表与浅copy的列表中的子对象也会随之改变,因为此时复杂对象中的子对象作为公共对象,浅copy时,新的列表还是引用的原列表中的子对象。而深copy则不一样,深copy是进行递归复制的,将列表的所有层都进行了复制,所以原列表中子对象元素的变化不会导致深copy的列表中的子对象的变化。

初学者,如有分析的不正确的地方,欢迎交流讨论。

原文地址:https://www.cnblogs.com/yangshijia/p/8711052.html