问题背景
使用a = [[0]*6]*5
新建了一个全0二维数组,在使用a[0][1] = 1
对其中一个元素赋值时,发现对列1生效:
a = [[0]*6]*5
a[0][1] = 1
print(a)
# output:[[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]]
问题原因
https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/
使用列表乘法创建二维列表是一种浅拷贝方式,相乘时并没有生成新的整数对象,而是创建了新的变量,并指向原整数对象。也就是说,在初始化发生后,实际只有一个整数对象0产生。
当赋值arr[1][0]=1
发生时,会创建一个新的整数对象1,此时里层1维列表的下标为0的arr[1][0]
会指向新的整数对象1,而外层的列表仍然指向唯一的里层1维列表,所以外层列表的下标此刻指向的都是同一列表,下标并未生效。
所以会出现整列赋值被改变。
我们用查看内存地址的方法,可以看到a[0]
和a[1]
地址相同:
a = [[0]*6]*5
a[0][1] = 1
print(a)
# id(): actual memory address
print(id(a[0]))
print(id(a[1]))
'''output
[[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]]
2536892439936
2536892439936
'''
解决方案
使用列表推导式:
https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions
rows, cols = (5, 5)
arr1 = [[0 for i in range(cols)] for j in range(rows)]
arr2 = [[0]*rows for _ in range(cols)]
附
浅拷贝和深拷贝
https://www.geeksforgeeks.org/copy-python-deep-copy-shallow-copy/
浅拷贝就是创建一个复杂变量,该变量的成员均为源对象所有子对象的引用;
而深拷贝就是创建一个复杂变量,该变量的成员为源对象所有子对象的拷贝;