浅拷贝和深拷贝的区别?

概述:

  1.   浅拷贝可以使用列表自带的copy()函数(如list.copy()),或者使用copy模块的copy()函数。深拷贝只能使用copy模块的deepcopy(),所以使用前要导入:from copy import deepcopy
  2.   如果拷贝的对象里的元素只有值,没有引用,那浅拷贝和深拷贝没有差别,都会将原有对象复制一份,产生一个新对象,对新对象里的值进行修改不会影响原有对象,新对象和原对象完全分离开。
  3.   如果拷贝的对象里的元素包含引用(像一个列表里储存着另一个列表,存的就是另一个列表的引用),那浅拷贝和深拷贝是不同的,浅拷贝虽然将原有对象复制一份,但是依然保存的是引用,所以对新对象里的引用里的值进行修改,依然会改变原对象里的列表的值,新对象和原对象完全分离开并没有完全分离开。而深拷贝则不同,它会将原对象里的引用也新创建一个,即新建一个列表,然后放的是新列表的引用,这样就可以将新对象和原对象完全分离开。

详解:

首先就上面第二点进行讲解,这里用到一个工具,Python Tutor(http://www.pythontutor.com)是一个对 Python 运行原理进行可视化分析的工具。如下截图。

        这里我们可以看到代码区跟运行原理的图像分析,这里使用copy()函数对列表aa进行拷贝,结果赋值给bb,可以看到内存里新创建一个列表,bb指向的就是这个新创建的列表,跟原本的aa是两个不同的列表,接下来我们对bb[0]的值进行修改为9,看下会如何变化:

           很明显,修改的值是bb列表的值,aal列表没有变化。接下来我们看看深拷贝的:

       看到代码区第3行,这里我们把拷贝函数换成深拷贝函数deepcopy(),然后我们看到右边图像区,很明显bb也是新创建的一个列表,与aa不同,这时我们再对bb[0]的值进行修改为9,可以看到bb列表里的值改变了,aal列表里的没有。到这里,我们已经验证了上面概述里的第二点。接下来让我们看看最重要的第三点的验证:

这里我们对aa列表做了修改,在aa列表里多添加了一个列表[4,5],然后使用copy()函数对aa进行拷贝赋值给bb,此时看到右边的图像,bb虽然是在内存中新创建了一个列表,但是其index=3的位置存放的还是跟aa列表中一样的引用,他们都指向同一个列表[4,5]。此时我们再修改bb列表里[4,5]中的4为9,执行第四行代码,看下效果:

很明显,bb里的值改变了,aa里的值也改变了。下面再看看使用深拷贝函数deepcopy()会发生什么?

这里我们把上面的代码第三行改一下,使用深拷贝函数拷贝aa列表,单点运行到第三行代码,此时我们看到内存里新创建了bb列表,还有就是可以看到bb列表index=3的位置的也是重新创建了新的列表[4,5],很明显区别于浅拷贝,这时,我们再执行第四行代码,修改下bb列表的[4,5]中的4的值为9,看下效果:

很明显只改变bb列表里列表[4,5]中的4为9,aa中的没有改变,因为它跟原aa列表指向的引用是不同的。这也充分验证了我们概述里讲到的第三点。

   看了网上那么多介绍,还是自己总结一下并做记录,印象最深。

猜你喜欢

转载自blog.csdn.net/qq_34493908/article/details/81560546