浅拷贝和深拷贝的区别在于,浅拷贝只复制对新列表的引用(引用可以理解为地址),并没有创建新的对象。深拷贝创建一个新对象并将该对象保存在一个新地址。浅拷贝和深拷贝对可变序列和不可变序列的影响不同。可变序列的浅拷贝可能会产生意想不到的结果。参见示例1示例1>>>a=[[1],2,3,4]>>>b=list(a)>>>a[0].append(0)>>>a[[1,0],2,3,4]>>>b[[1,0],2,3,4]对于复制列表,最简单的方法是使用内置的类型构造器list(),你也可以使用[:]进行复制。构造函数和[:]都是浅拷贝。从示例1可以看出,修改了a的第0个元素,但是b也发生了变化。为什么?我首先需要了解a和b之间发生了什么?请参见下面的图1。因为浅拷贝只是将引用复制到新列表中,它们的引用还是一样的,a和b的第0个元素指向列表[1],因为列表是可变序列,可以就地修改,所以修改后向引用不变。这就导致a的修改会带来b的改变。看例2例2>>>a=[1,2,3,4]>>>b=list(a)>>>a[0]=0>>>a[0,2,3,4]>>>b[1,2,3,4]例2中a的修改不带b的变化。他们之间发生了什么?请参见下面的图2。因为是浅拷贝,a和b原来的引用是一样的,然后修改a的第0个元素。由于这个元素是一个不可变序列,只能通过创建一个新对象来改变,所以a的第0个元素对第0个元素的引用发生了变化,但这并不影响对b的第0个元素的引用。好吧,我们再看一个更复杂的例子,见例3例3>>>l1=[1,[2,3,4],(5,6,7)]>>>l2=list(l1)>>>l1.append(10)#1>>>l1[1].remove(3)#2>>>l2[1]+=[8,9]#3>>>l2[2]+=(10,11)#4l2modificationhasnoeffectonl2l2modificationhasaneffectonl2l2modificationhasaneffectonl1l2modificationhasnoeffectonl1shallowcopy的结果可能不是你想要的,那么deepcopy怎么办?.实际上copy模块提供的copy和deepcopy函数可以对任意对象进行浅拷贝和深拷贝,见例4。例4>>>importcopy>>>l1=[1,[2,3,4],(5,6,7)]>>>l2=copy.deepcopy(l1)>>>l3=copy.copy(l1)>>>l1[1].remove(3)>>>l1>>>l1=[1,[2,4],(5,6,7)]>>>l2>>>l1=[1,[2,3,4],(5,6,7)]>>>l3[1,[2,4],(5,6,7)]l2是l??1的深拷贝,l3是l2的浅拷贝修改l1的第一个元素。虽然这个元素是一个可变对象,它影响l3,但不影响l2。因为l2是深拷贝的原因,所以创建了一个新的对象,有了一个新的引用,可以说和l2没有关系,只是内容相同而已。最后看一个有趣的现象,见例5例5>>>l1=[1,[2,3,4],(5,6,7)]>>>l1.append(l1)>>>l1[1,[2,4],(5,6,7),[...]]看到l2的最后一个元素很神奇[...],这是怎么回事?看看下面图3中的引用,加油!可以看出,列表最后一个元素的引用指向了自己,而自己的最后一个元素仍然指向自己。这是一个无限循环引用,所以多了[…],有错误的请指出。更多精彩文章请关注我公众号:CVpython,专注于Python与计算机视觉的分享。我们坚持原创,不时更新。希望文章能给你启发,共同进步。
