深拷贝和浅拷贝都是用于复制对象的概念。浅拷贝在复制对象时,仅复制其引用,而非复制对象本身。这意味着原对象和新对象都指向相同的内存地址,修改一个对象会影响另一个对象。如果有一点C语言基础,那么可能马上意识到,浅拷贝相当于复制了指针,而深拷贝则相当于新开辟了一块内存。。
现有一个变量a,这个a可能占据大量内存,但在我们看来,这就是一个a而已,换言之,a或许只是提供了一个内存范围,起到一个寻址,或者指示的作用。
当我们调用a的时候,解释器识别了a这个变量,然后将通过a找到了一大片内存。
所谓浅拷贝,比如b=copy.copy(a)
,这个过程中,仅仅是把a
这个索引赋值给了b
,至于a
所指向的那一大片内存,是纹丝不动的。
import copy
a = [i for i in range(100)]
b = a # = 默认浅拷贝
id(a)
# 2236793528448
id(b)
# 2236793528448
id(a[0])
# 2236754585872
id(b[0])
# 2236754585872 和 a[0]是同一位置
由此导致的结果就是,如果那片内存发生了什么变化,a
和b
也将同步变化。
print(a[0],b[0])
# 输出 0,0
a[0] = 255
print(a[0],b[0])
# 输出255 255
深拷贝,则可以重新开辟一片内存,让这个新开辟的内存,处处与a
指向的那片内存相等。所以,当b=copy.deepcopy(a)
被执行后,a
和b
将变得互不相干。
a = [i for i in range(100)]
b = copy.deepcopy(a)
id(a[0])
id(b[0])
# 这时a[0]和b[0]还是指向同样的位置
之所以a[0]
和b[0]
还是指向同一个位置,是因为二者的值是相同的,a[0]==b[0]==0
,而0
这个对象在整个python
运行时中只有一个,所以无论什么对象,只要其中有0
,那么这个对象都会指向同一位置
a = [i for i in range(50000)]
c = [i for i in range(50000)]
id(a[0]) == id(c[0])
# a和c没有任何关系,但二者指向了统一内存位置 True
为了确认的确执行了设拷贝,可以更改一下a[i]
的值,可以看到b[i]
并不会跟着改动。
a[0] = 1
id(a[0])==id(b[0])
# False 即更改a[0]的值后,a[0]和b[0]指向的内存发生了变化
由于深拷贝需要操作大量内存,也会新建大量内存,所以一般情况下,python的赋值号执行的是浅拷贝。
如果不想导入copy
模块,同时还想新建一个变量,那么可以结合对象的特点来使用运算符,例如
a = [i for i in range(50000000)]
b = a + []
如果把内存理解为一个宝藏,那么浅拷贝相当于标记了一个领地,而深拷贝相当于另外再挖一个宝藏。