为何切片复制列表后操作仍修改原矩阵?如何保持输入列表不变
解决列表副作用:如何确保函数中的列表输入保持不变
这个问题我之前也踩过坑!你遇到的问题核心在于:m = matrix[:]做的是浅拷贝——它只会复制外层的列表容器,但里面的每个子列表(也就是矩阵的每一行)还是和原列表matrix指向同一个内存对象。所以当你修改m里的子列表(比如调用i.reverse()或者交换元素值)时,实际上修改的是原列表里的子列表,自然会让myl也跟着变。
下面给你几种靠谱的解决方法:
方法1:用深拷贝彻底隔离原列表
Python的copy模块里的deepcopy可以递归复制所有层级的嵌套结构,让新列表和原列表完全独立,互不影响:
import copy def matrixflip(matrix, d): m = copy.deepcopy(matrix) # 深拷贝,把所有嵌套的子列表也复制一份 length = len(m) if d == 'h': for i in m: i.reverse() return m elif d == 'v': for i in range(length//2): for j in range(len(m[0])): m[i][j], m[length-1-i][j] = m[length-1-i][j], m[i][j] return m else: return m myl = [[1, 2], [3, 4]] p = matrixflip(myl,'v') print(p) # 输出 [[3, 4], [1, 2]] print(myl) # 输出 [[1, 2], [3, 4]],原列表完美保留
方法2:手动复制子列表(不用额外模块)
如果你不想导入copy模块,可以用列表推导式手动复制每个子列表,这样也能实现“深拷贝”的效果:
def matrixflip(matrix, d): # 逐个复制每个子列表,生成完全独立的新矩阵 m = [row[:] for row in matrix] length = len(m) if d == 'h': for i in m: i.reverse() return m elif d == 'v': # 这里顺便优化了代码:直接交换整个行,比逐个元素交换高效多了 for i in range(length//2): m[i], m[length-1-i] = m[length-1-i], m[i] return m else: return m myl = [[1, 2], [3, 4]] p = matrixflip(myl,'v') print(p) # [[3, 4], [1, 2]] print(myl) # [[1, 2], [3, 4]]
方法3:用Pythonic的方式直接生成结果(最简洁)
其实翻转操作完全可以用列表切片直接生成新列表,连提前拷贝都不用,代码更简洁,还天然不会影响原列表:
def matrixflip(matrix, d): if d == 'h': # 水平翻转:对每个行做切片反转,生成新列表 return [row[::-1] for row in matrix] elif d == 'v': # 垂直翻转:直接反转整个外层列表 return matrix[::-1] else: # 返回原列表的浅拷贝,避免后续意外修改原列表 return matrix.copy() myl = [[1, 2], [3, 4]] p = matrixflip(myl,'v') print(p) # [[3, 4], [1, 2]] print(myl) # [[1, 2], [3, 4]]
最后再划个重点
处理嵌套的可变对象(比如列表里套列表)时,浅拷贝(像matrix[:]或者list(matrix))只复制外层结构,内层的子列表还是共享引用。想要原列表完全不受影响,要么用deepcopy,要么手动复制每个内层的可变对象,或者像第三种方法一样直接生成全新的结果列表。
内容的提问来源于stack exchange,提问作者Tushar Singh
相关产品推荐
相关产品推荐

