Python的浅拷贝与is的问题

>>> names = [1,2,3]
>>> names = [1,2,[3,4]]
>>> n = names.copy()
>>> n is names
False

is是比较 变量中存储的内存地址吗?这样的话,n和names中存储的内存地址不应该是相同的吗?
这个知识点一直没能理解...
求助...

阅读 1.7k
3 个回答

(1) is是比较两个引用是否指向了同一个对象(引用比较)。

clipboard.png

所以,在修改a的同时,b随之改变,这也是毋庸置疑的。如图:

clipboard.png

(2) n和copy中的地址不相同。你之所以认为相同是因为你把浅拷贝和直接赋值(也有人叫它浅拷贝的一种形式)形式的运算搞混了,或者说你还没有理清楚它们的区别。

例如刚才的“b = a” 就是直接赋值(引用操作),而你的n = names.copy()是浅拷贝。

浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制。(或者说只拷贝父对象,不会拷贝对象的内部的子对象。)

这句话一出,你可能会马上明白,但你也可能一脸懵逼,举个例子来解释一下:

clipboard.png

做个图解可能更方便理解:

clipboard.png

步骤详解:
(1)创建两个列表a,b。
(2)创建列表c,它的c[0],c[1]分别保存的是a,b的引用值。
(3)通过"e = c.copy()"拷贝一份出来,记住:现在只拷贝了父层,父层只有c[0],c[1],那现在就只拷贝这一层对象,而c[0],c[1]指向的内容,我不复制(请好好理解这句话)
(4)e的第一层(e[0],e[1])分别指向了列表a,b.从图中看,e和c的内容相等(也确实相等)。但是e,c的箭头并没有指向同一个对象!!!e在c.copy()的时候开辟了空间,所以导致你的is比较返False.如图:

clipboard.png

大概就解释到这,小生不才,言语表达能力可能不是很难好,希望能帮到你。

is比较两个变量是否指向同一对象,copy()之后生成了新的对象,所以is就返回False了


>>> a = 1
>>> names = [a]
>>> n = names.copy()
>>> n is names
False
>>> n[0] is names[0]
True
n和names中存储的内存地址不应该是相同的吗?

首先要明确你想对n和names比较,还是两者内部元素的比较。

names由于是一个list(mutable),copy操作才为n开辟了内存空间,所以这里n和names用is比较是False。

而另一种immutable的copy情况:

>>> import copy
>>> a = (1, 2)
>>> copy.copy(a) is a
True
推荐问题