记得面试的时候面试官问我浅复制和深复制有什么区别。只用过python里可变数据类型的copy函数的我一脸懵逼,xjb说了一点,结果自然惨不忍睹。。我回来一查,原来他说的是copy库。。敲里吗啊,copy库又不是一定要用,老子也不是学计算机的,哪知道这么细。。哎,终究是自己才疏学浅,怪不得别人。
python中的unhashable数据类型都自带copy函数。这里的copy其实是所谓的浅拷贝,什么是浅拷贝呢?
这就涉及到了python的赋值机制了。
看一个例子:
x=[1,2,[3,4]]
python在生成这个列表的时候先为1,2,3,4分配内存pos1,pos2,pos3,pos4,然后为列表[3,4]分配一段内存 pos5 ,它包含2个位置,分别指向内存pos3,pos4。然后为列表[1,2,[3,4]]分配一段内存 posa,它包含3个位置,分别指向内存pos1,pos2,pos5, 最后再让变量 x 指向这个列表。
内存 命名空间
pos1 : PyInt(1)
(不可变)
pos2 : PyInt(2)
(不可变)
x : posa
pos5 : PyList(pos3,pos4)(可变)
posa : PyList(pos1, pos2, pos5)
(可变)
pos6 : Pyint(5)
(不可变)
y=x.copy()
当python接收到浅拷贝命令后,为拷贝的列表分配一个新的内存posb,它同样也包含3个位置,分别指向内存pos1,pos2,pos5。
当列表x中的元素改变时:
x.append(5) // python为5分配一个新的内存pos6,此时pos0包含4个位置,分别指向内存pos1,pos2,pos5,pos6。
或者
x[0]=5 // python为5分配一个新的内存pos6,此时pos0包含3个位置,分别指向内存pos2,pos5,pos6。
这时候拷贝列表的内存还是指向pos1,pos2,pos5,也即不会发生变化。
当x中的元素的元素发生改变时:
x[2][0]=0
python为0分配一个新的内存,pos5的指向也会改变,但是posa,posb依然包含三个位置,分别指向pos1,pos2,pos5,也即x=y=[1,2,[0,4]
浅拷贝只拷贝父对象,不拷贝对象的子对象。因此当父对象改变时,拷贝不变。当子对象改变时,浅拷贝跟着变。
还可以导入copy库来创建浅拷贝
方法是
import copy
y=copy.copy(x)
创建深拷贝:
y=copy.deepcopy(x)
深拷贝除了拷贝父对象,还拷贝对象的子对象。用上面的例子来讲,不同之处在于深拷贝为元素[3,4]又分配了一个新的内存,指向pos3,pos4,这样,当列表x无论改变其元素还是其元素的子元素都不会影响深拷贝列表y的内存指向,也即y与x相互独立了。