详解python中的浅拷贝和深拷贝

来源:互联网 发布:火猫解说 收入 知乎 编辑:程序博客网 时间:2024/06/05 00:50

一、定义
首先比较直观的说一下,python里面的浅拷贝和深拷贝
浅拷贝:就是对引用的拷贝,值拷贝父对象
深拷贝:就是对对象的资源的拷贝

首先下面通过我们常常说的赋值来看一下:

root@ubuntu16:~# python3
Python 3.5.2 (default, Sep 14 2017, 22:51:06)
[GCC 5.4.0 20160609] on linux
Type “help”, “copyright”, “credits” or “license” for more information.

a = [1,2,’a’,’b’]
b = a
b
[1, 2, ‘a’, ‘b’]
a
[1, 2, ‘a’, ‘b’]
a.append(‘c’)
a
[1, 2, ‘a’, ‘b’, ‘c’]
b
[1, 2, ‘a’, ‘b’, ‘c’]
id(a)
140489872264776
id(b)
140489872264776

在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。上面首先定义一个列表a,然后将a赋值给b,可以看到a和b的值是一样的,我们在修改a的值的时候【比如添加一个字符c】,b的值也是一样的跟着变化的,这是因为a和b分别是两个标签,但他们引用的是同一个地址空间,我们能看到id(a),id(b)是同样的值,即是同一个地址空间。

二、举例解释:
root@ubuntu16:~# python3
Python 3.5.2 (default, Sep 14 2017, 22:51:06)
[GCC 5.4.0 20160609] on linux
Type “help”, “copyright”, “credits” or “license” for more information.

import copy
首先导入copy模块,因为后面要用到copy函数
a = [1,2,3,4,[‘a’,’b’,’c’],{‘name’:’liang’}]
b = a
b
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’], {‘name’: ‘liang’}]
在这里还是把a的值赋值给b
c = copy.copy(a)
c
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’], {‘name’: ‘liang’}]
这个copy函数就是浅拷贝,把a的值浅拷贝给c,输出c的值发现和a是一模一样的
id(a)
140484710365256
id(b)
140484710365256
id(c)
140484717979336
分别把a,b,c的地址空间id查出来可以看到,a和c是不一样的,这就是浅拷贝的本质,是对父对象的拷贝,相当于b是a的备份,a和b占用的地址空间是不一样的。
a.append(‘d’)
a
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’], {‘name’: ‘liang’}, ‘d’]
b
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’], {‘name’: ‘liang’}, ‘d’]
c
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’], {‘name’: ‘liang’}]
所以在对对象a执行append操作的时候,就会看到,c的值不会变的,因为操作的是两个不一样的地址空间。
a[4].append(‘d’)
a
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’, ‘d’], {‘name’: ‘liang’}, ‘d’]
c
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’, ‘d’], {‘name’: ‘liang’}]
id(a[4])
140484710449416
id(c[4])
140484710449416
但是对对象a的其中一个元素执行append()操作的时候,就会出现,c里面对应的元素还是会跟着变化的。通过查看地址空间的id可以看到,虽然a,c两个对象占用的地址空间不一样,但是c是a的浅拷贝,c元对象里面的元素仍然和a对象里面的元素占用一样的地址空间【例如上面的a[4]和c[4]】
下面我们用深拷贝:
d = copy.deepcopy(a)
d
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’, ‘d’], {‘name’: ‘liang’}, ‘d’]
a[4].append(‘e’)
a
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’, ‘d’, ‘e’], {‘name’: ‘liang’}, ‘d’]
d
[1, 2, 3, 4, [‘a’, ‘b’, ‘c’, ‘d’], {‘name’: ‘liang’}, ‘d’]
id(a[4])
140484710449416
id(d[4])
140484710365832

我们还是对a进行深拷贝为d,然后还是对a[4]元素进行append操作,发现c对象的c[4]元素并没有发生改变,通过查看这个元素的id可以看到,两个元素的地址空间是不一样的,所以这才是真正意义上的完全的拷贝。简单的来说就是,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存,也就是说,在浅拷贝情况下,不同引用指向的是同一块内存,改其中一个引用,那么其他引用也会跟着改变 ,浅拷贝就是对整个父对象的拷贝。

原创粉丝点击