写leetcode的时候被这个坑了,查询并实验后终于弄清楚,特此记录。
本文参考链接
python的赋值操作分三种:直接赋值、浅拷贝、深拷贝
直接赋值
比如
a = [1,2,3]
b = a
这时候b和a就是同一个对象的不同命名而已,指向的都是同一块内存。
深拷贝
import copy
a = [[0,0,0],[1,1,1],[2,2,2]]
b = copy.deepcopy(a)
b[0][1] = 5
print(a)
for x in a:
print(id(x))
for x in b:
print(id(x))
结果如图:
可见,这才是我们想要的拷贝,两者指向的对象地址都不同,改动一方不会对另一方产生影响。
但是这里的对象不同仅限于列表对象不同,而python的原子类型都是固定的对象,比如int等。像如果
for x in a[0]:
print(id(x))
出来的三个0的地址都是一样的,都指向0这个对象所在的内存。
浅拷贝
除了直接赋值和深拷贝,剩下的基本都是浅拷贝。比如
1、切片操作:b = a[:] 或者 b = [each for each in a]
2、工厂函数:b = list(a)
3、copy函数:b = copy.copy(a)
还是这个例子:
import copy
a = [[0,0,0],[1,1,1],[2,2,2]]
b = a.copy() # 或者b = copy.copy(a)
b[0][1] = 5
此时你输出a的值,会发现a也随着b改变了。
但是你去判断a is b
他会输出False,因为a和b确实不是同一个对象了。你在b后面append些啥,也不影响a。
原因是什么呢?
如果你
print(a)
for x in a:
print(id(x))
for x in b:
print(id(x))
就会发现,a和b它们里面的元素指向的还是一样的地址。
所以,当你直接修改子列表的元素的值时,那就是在这块内存上改(或许不准确,我也没细究python底层内存机制是什么),所以会影响到同是引用这块内存的a。