Python列表拷贝疑问:修改嵌套列表拷贝为何改变原列表?
为什么修改嵌套列表的拷贝会影响原列表?
嘿,这个问题我刚学Python的时候也踩过一模一样的坑!本质上是浅拷贝和深拷贝的区别在搞鬼,咱们一步一步理清楚:
先看两种列表的本质区别
你提到的两种列表看起来都是列表,但内部元素的类型不一样:
- 第一种是一维列表:
a = [1,2,3,4],里面的元素都是整数这种「不可变类型」(int、str、tuple这些都是不可变的) - 第二种是嵌套列表:
a = [[1,2],[3,4]],里面的元素是另一个列表,属于「可变类型」(list、dict、set这些都是可变的)
浅拷贝的局限性
你大概率是用了list.copy()或者切片a[:]来做拷贝,这些都是浅拷贝操作:
- 对于一维的不可变元素列表:浅拷贝会创建一个新列表,每个元素是原元素的引用。但因为元素是不可变的,当你修改拷贝里的元素时,其实是把拷贝里的引用换成了新的对象(比如把
b[3]从指向4改成指向100),原列表的引用不受影响,所以原列表不会变。 - 对于嵌套列表:浅拷贝只会拷贝外层列表的结构,里面的子列表只是把引用复制了一份。也就是说,原列表
a和拷贝后的列表b里的子列表是同一个对象!比如a[1]和b[1]指向的是内存里的同一个[3,4]列表,你修改b[1][1] = 100,其实是直接修改了这个共享的子列表,原列表自然也跟着变了。
用代码验证一下
你可以试试打印元素的内存地址,就能看明白:
a = [[1,2],[3,4]] b = a.copy() # 打印子列表的内存地址,会发现是同一个 print(id(a[1])) # 比如输出:140703371234560 print(id(b[1])) # 输出和上面完全一样! # 修改拷贝的子列表 b[1][1] = 100 print(a) # 输出 [[1,2],[3,100]],原列表确实变了
怎么解决这个问题?
如果想修改嵌套列表的拷贝但不影响原列表,就得用深拷贝——它会递归地拷贝所有嵌套的可变对象,确保原列表和拷贝列表完全独立:
import copy a = [[1,2],[3,4]] b = copy.deepcopy(a) # 现在子列表的内存地址不一样了 print(id(a[1])) print(id(b[1])) # 和上面不同 # 修改拷贝的子列表,原列表不受影响 b[1][1] = 100 print(a) # 输出 [[1,2],[3,4]] print(b) # 输出 [[1,2],[3,100]]
简单总结一下:浅拷贝只拷贝外层结构,嵌套的可变元素还是共享引用;深拷贝会把所有层级的元素都拷贝一遍,彻底断开和原列表的关联。
内容的提问来源于stack exchange,提问作者Mathe
相关产品推荐
相关产品推荐

