- 背景
- 问题
- 思考
- 结论
背景
在使用Python3做洛谷B2108题的过程中,需要将原始数据进行模糊化(见题目)处理后更新二维数组,那么就涉及到一个问题:如果在原数组中修改,将影响到后续数据的运算结果,于是对原始二维数组进行了浅拷贝,创建了一个新的二维数组,将原始二维数组用于提取原始数据,运算后的结果写入新的二维数组。但是经过尝试,发现一旦新数组中底层的元素被改动,原始数组也将收到影响。
matrix = [ [100, 0, 100, 0, 50], [50, 100, 200, 0, 0], [50, 50, 100, 100, 200], [100, 100, 50, 50, 100], ] temp_matrix = matrix.copy() [print(i) for i in matrix] print() [print(i) for i in temp_matrix]
执行以上代码,输出结果为:
[100, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100] [100, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100]
对temp_matrix中的元素进行修改之后再进行输出:
temp_matrix[0][0] = matrix[1][2] [print(i) for i in matrix] print() [print(i) for i in temp_matrix]
执行以上代码,输出结果为:
[0, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100] [0, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100]
可见两个二维数组虽然看起来是不同的对象,但是在对其中一个进行修改的同时,另一个也将受到影响。
问题
第二个二维数组是第一个二维数组浅拷贝而来,通过id()方法查看两个对象的内存地址也不相同,为何仍会互相影响?
print(id(matrix)) print(id(temp_matrix))
执行以上代码,输出结果为:
2509216600384 2509216600448
思考
经过反复测试,不论是直接对二维数组进行浅拷贝,还是遍历二维数组后逐个添加进新的二维数组,之后在对新二维数组中的数字进行改动的时候,都会影响原始二维数组中的数据。
temp_matrix = [] for i in matrix: temp_matrix.append(i) temp_matrix[0][0] = matrix[1][2] [print(i) for i in matrix] print() [print(i) for i in temp_matrix]
执行以上代码后结果仍然相同,两个二维数组中的数据都发生了改变。
但是
如果将二维数组中嵌套的一维数组作为一个整体进行改动,则不会影响原始数据:
temp_matrix[0] = matrix[1] [print(i) for i in matrix] print() [print(i) for i in temp_matrix]
执行以上代码,输出结果为:
[100, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100] [50, 100, 200, 0, 0] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100]
这是因为当原对象存在多层嵌套的情况下,浅拷贝copy()只拷贝了调用这个方法的这一层的数据结构,这一层所包含的数据变化时,是不会相互影响的,但是当原数据对象内部嵌套数据中的数据发生变化后,相应的浅拷贝后的对象也会发生变化。
在上面的例子中,temp_matrix是对matrix的浅拷贝,指的是在这两个列表中的元素互不影响,但是由于这两个列表中的元素还存在内部结构(也都是列表),故而浅拷贝的互不影响原则不会作用于深层的数据,所以发生了某种“量子纠缠”效应。
这就像是一所学校,按照同样的蓝图建设了许多教室,里面有相同的墙体,窗户,门,桌椅,黑板,喇叭,其中某一间教室因为喇叭坏了,换了一个新型号,这一事件不影响其他的教室;但是当广播室更换播放的音乐的时候,所有教室的喇叭发出的声音都会改变。
结论
要想使两个二维数组甚至更多层次的数据结构中的数据完全不关联,应该使用以下方法:
temp_matrix = [] for i in matrix: temp_matrix.append(i.copy()) temp_matrix[0][0] = matrix[1][2] [print(i) for i in matrix] print() [print(i) for i in temp_matrix]
执行以上代码,输出结果为:
[100, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100] [200, 0, 100, 0, 50] [50, 100, 200, 0, 0] [50, 50, 100, 100, 200] [100, 100, 50, 50, 100]
可见,此方法,在最底层的数据结构中进行了浅拷贝,从根本上将两个数据完全隔绝开,回到题目中,可以实现从原始二维数组中提取数据,进行计算后改写新的二维数组:
# 获取输入 temp = input().split() n = int(temp[0]) m = int(temp[1]) # 构造原始二维数组 matrix = [list(map(int,input().split())) for _ in range(n)] # 构造新的二维数组 temp_matrix = [i.copy() for i in matrix] # 遍历行 for row in range(1,n-1): # 遍历列 for col in range(1,m-1): # 从原始数组中取值,写入新数组 temp_matrix[row][col] = round((matrix[row-1][col] + matrix[row+1][col] + matrix[row][col-1] + matrix[row][col+1] + matrix[row][col])/5) # 输出 [print(i) for i in temp_matrix]