问题描述
我正在尝试编写简单的函数,该函数将返回两个矩阵的总和(嵌套列表)。我不明白为什么下面的代码无法按预期工作。请注意,所有打印步骤都可以,但是最后的结果却不正确。
代码:
matrix_a = [[1,2,4],[0,1,3],[2,8]]
matrix_b = [[0,3,1],[5,4,2],[8,6]]
rows = len(matrix_a)
columns = len(matrix_a[0])
result = [[0] * columns] * rows
for x in range(rows):
for y in range(columns):
result[x][y] = matrix_a[x][y] + matrix_b[x][y]
print(f'[{x}][{y}]: {matrix_a[x][y]} + {matrix_b[x][y]} = {result[x][y]}')
print(result)
输出:
[0][0]: 1 + 0 = 1
[0][1]: 2 + 3 = 5
[0][2]: 4 + 1 = 5
[1][0]: 0 + 5 = 5
[1][1]: 1 + 4 = 5
[1][2]: 3 + 2 = 5
[2][0]: 2 + 8 = 10
[2][1]: 2 + 2 = 4
[2][2]: 8 + 6 = 14
[[10,14],[10,14]]
您能告诉我如何解决它,对我来说更重要的是,为什么最后一行被复制了三遍?
解决方法
执行[[0] * columns] * rows
时,您将创建一个包含3个引用的列表。
它等效于以下代码:
a = [0,0] # a = [0] * columns
result = [a,a,a] # result = [a] * rows
因此,当您执行result[0]
,result[1]
和result[2]
时,实际上是指与a
相同的基础内存。由于它们都引用同一个对象,因此当您执行最后三行时
[2][0]: 2 + 8 = 10
[2][1]: 2 + 2 = 4
[2][2]: 8 + 6 = 14
您实际上是在修改同一基础实体a
(在我们的示例中)。
如果要以编程方式分配结果数组,则必须这样做
result = [[0] * columns for _ in range(rows)]
附录:
现在,您可能会问为什么[0] * columns
没有显示相同的行为,即。您的整个结果为什么不排列值14
。这与Python管理底层内存的方式有关,它与数据类型是否可微复制(例如原语)以及数据类型是否不可变(例如元组vs列表)有很大关系。
问题是您初始化结果的方式,
[[0] * columns] * rows] # results in reference being same,
上面发生的事情是您正在创建单个数组[0,0,0]并对其进行3次引用。
将其更改为
[[0] * columns] for _ in range(rows)]. # separate lists would be created.
matrix_a = [[1,2,4],[0,1,3],[2,8]]
matrix_b = [[0,3,1],[5,4,2],[8,6]]
result = []
for row in range(len(matrix_a)):
x = []
for col in range(len(matrix_a[row])):
summed_row_array = matrix_a[row][col] + matrix_b[row][col]
x.append(summed_row_array)
result.append(x)
print(result)