python实现矩阵乘法(不用numpy)

python实现矩阵乘法

    • 不使用其他库的情况下实现矩阵乘法

不使用其他库的情况下实现矩阵乘法

在不使用numpy库的情况下实现矩阵乘法,看起来很简单,但这之中也是存在坑的。比如如下代码:

class mat_mul():
	def mm(self,A,B):
		row_len = len(A)
		column_len = len(B[0])
		cross_len = len(B)
		res_mat = [[0] * column_len] * row_len 
		for i in range(row_len):
			for j in range(column_len):
				for k in range(cross_len):
					temp = A[i][k] * B[k][j]
					res_mat[i][j] += temp	
				print "==="
		print res_mat

def main():
	A = [[1,1,1],[2,0,2]]
	B = [[0,1],[1,0],[1,1]]
	m = mat_mul()
	m.mm(A,B)
if __name__ == '__main__':
	main()

结果本应该是
在这里插入图片描述
可是最终程序运行完结果却是
在这里插入图片描述
最终将中间结果输出,发现问题出现在矩阵初始化阶段:

res_mat = [[0] * row_len] * column_len

这里我想初始化一个row_len*column_len的全0矩阵,所以[0]*row_len,再将新生成的list乘以coluimn_len。这里问题就出现了:
python中,如果将list 乘以k,表面上看起来是将list复制了k份,然而事实证明这k个list所指向的内存中的对象只有一个,即原始的list,也就是说如果其中一个list被改变,k个list都会跟着变。
举例:

c = [[0]*2]*2
print "before:",c
c[0][1] = 3
print "after:",c

最终输出结果:
在这里插入图片描述

可以看到我只给第0行的第一个元素赋值3,这却导致第1行的第一个元素跟着改变。
可以使用python的id函数查看每个列表的在内存内的地址:

print id(c[0]),id(c[1])
39642936 39642936

最终发现其地址是一样的。
所以,正确的初始化方法是:

res_mat = [[0] * row_len for i in range(column_len)]

这样最终的结果就没有问题啦。
原来一直以为了解python,但是对于其底层实现还掌握的太少太少。以后应该多注意这方面的学习。
PS:
列表的复制方法:

lista=[1,[2,3]]
listb=lista[:]
listb=[i for i in lista]
listb=copy.copy(lista)
listb=copy.deepcopy(lista)

只有第五种是完全拷贝,其他在不同场合下都会出现以上问题。

你可能感兴趣的:(python,python,矩阵乘法,列表复制)