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)
只有第五种是完全拷贝,其他在不同场合下都会出现以上问题。